perm filename MIX1[MIX,SYS] blob
sn#200557 filedate 1976-02-07 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00058 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00007 00002 TITLE MIX
C00013 00003 COMMENT Registers 0-7 and 15 are used to simulate MIX's
C00016 00004 SUBTTL MIXLOG - LOG OF ADDITIONS AND CORRECTIONS
C00029 00005 SUBTTL MIXDPY - III manipulations
C00034 00006 COMMENT This section has all the display facilities, including
C00042 00007 COMMENT If the PDP address of the word to be displayed is
C00045 00008 SUBTTL MIXDD DD manipulation routines
C00046 00009 Update DD screen ***
C00054 00010 Subroutine to see if a line needs to be updated
C00058 00011 COMMENT NOW WRITE ALL INFO TO THE DATA DISK BUFFER
C00063 00012 COMMENT TABLES USED BY DDUPD
C00066 00013 COMMENT ROUTINE TO REFRESH WHOLE SCREEN
C00067 00014 SUBTTL MIXBUT Handle "console buttons"
C00072 00015 QSTART: SETZB RJ, EXTIME EXTIME, RJ ← 0
C00076 00016 QSETUP: SETZ 10,
C00079 00017 COMMENT RESCN routine to scan the rest of the line of TTY input looking an
C00084 00018 BEGIN MIXBUG ↔ SUBTTL MIXBUG - Dynamic debugger for MIX machine
C00088 00019 comment INCHAR is a subroutine to read one char from the TTY and
C00090 00020 comment SCAN is a subroutine to return one input token. the token
C00093 00021 opdef scan [pushj p, .]
C00100 00022 comment EXPR is a subroutine to read in and evaluate an expression.
C00106 00023 comment WVAL is a subroutine to read in and evaluate a w-value.
C00111 00024 comment FPOINT is a table of byte pointers for depositing things
C00112 00025 comment INST is a subroutine to read an instruction.
C00116 00026 comment ADDR is a subroutine to read an expression and see whether
C00118 00027 comment GETSYM is a subroutine to find a symbolic expression for
C00121 00028 comment these are a couple of subroutines to do some outputting:
C00123 00029 comment MIXBUG is the starting address of the command interpreter.
C00125 00030 comment EXAMIN is what looks at core locations and displays what it sees.
C00129 00031 put out cell in symbolic instruction mode
C00137 00032 eb0: movei tac1, "+" assume positive
C00140 00033 es00: movei tac1,40
C00142 00034 en0: movei tac1,40
C00143 00035 dposit: addrc get address followed by ←
C00145 00036 comment BREAK and UBREAK are the places which handle
C00148 00037 comment JUMPER is (would you believe) what does the jumping
C00149 00038 comment XXXX is where we go to execute a particular instruction
C00150 00039 comment EQUAL is used to show things in different styles
C00151 00040 comment LF is where we display the next location
C00152 00041 SUBTTL MIXLOK - I/O interlocking.
C00158 00042 SUBTTL MIXMON - Central interpreter/monitor
C00161 00043 OPLST: NOP
C00162 00044 COMMENT Field specification:
C00163 00045 COMMENT Memory specification:
C00165 00046 COMMENT "Load" instructions.
C00167 00047 COMMENT "Store" instructions.
C00170 00048 COMMENT "Arithmetic" instructions.
C00175 00049 COMMENT "Address transfer" insructions
C00177 00050 COMMENT "Comparison" instructions.
C00179 00051 COMMENT "Jump" instructions.
C00182 00052 COMMENT Miscellaneous operators.
C00191 00053 SUBTTL MIXIO - I/O button routines
C00195 00054 COMMENT "Input-output" operations.
C00199 00055 COMMENT The IN instruction
C00203 00056 COMMENT The OUT instruction
C00209 00057 COMMENT These are the device specific sections.
C00218 00058 these are the other i/o related operations
C00223 ENDMK
C⊗;
TITLE MIX
MIXASM←←0 ;flag indicating complete MIX system, not just MIXAL
COMMENT ⊗
The summary given below is out of date: there are many more buttons.
A full description is in the write-up: MIX.DOC
This is a MIX simulator. The MIX machine being simulated has
a byte size of 64. At present, this machine has virtually no
automatic input/output facilities. However, it does have numerous
console buttons with the following effects:
"START" or "S"-- Type the word `start' followed 4 !'s; then
return to button mode. (When operational, this button
will initialize the timer and the program counter,
then begin execution at location 0000)
"GO" or "G"-- Type the word `go' followed by 4 !'s; then
return to button mode. (When operational, this button
will read a card into 0000-0015, then jump to
location 0000)
"LOAD" or "L"-- Type the word `load' followed by 4 !'s; then
return to button mode. (When operational, this button
will read a card into 0000-0015, then return to
button mode)
"CONT" or "C"-- Type the word `cont' followed by 4 !'s; then
begin execution at the instruction pointed to by the
program counter.
"HALT" or "H"-- Return to button mode. To halt while a
program is being executed, type a carriage-return.
"STEP" or "X"-- Execute a single instruction.
"DISP" or "D"-- Show the contents of rA, rX, rJ, the time (in
octal and in MIX cycles) shown by the timer, the base
address of the simulated core positions (the address
of location 0000 in octal), the PDP-10 location
pointed to by the program counter, and the most
recent MIX instruction executed.
"MEM" or "M"-- Prepare to read in four decimal digits and
then type the contents of that MIX location; if "X"
is typed instead of four digits, then leave "M" mode.
(i.e., you can get several locations each time you
press "MEM")
"ZXT"-- Zero out the timer.
"ZPC"-- Set the program counter to location 0000.
MIX words are represented by PDP-10 words on a 1-1 (into?)
basis according to the following table:
PDP-10 bits MIX byte
0- 5 sign (00=+, 40=-)
6-11 byte 1
12-17 byte 2
18-23 byte 3
24-29 byte 4
30-35 byte 5
Overall, the major emphasis has been on reasonable speed, but
extreme attention to details, with the idea that this would not be
used for actual operation of programs to any great degree, but would
be used to debug compilers, and so it is important to know when some
"undefined" operation occurs. I suspect that tables could be used to
a greater advantage. I also plan to write several more subroutines
so that the amount of PDP-10 memory used by the program is decreased.
I also think that there are several areas where the code could be
significantly improved, but it is probably not worth the expenditure
of time at this point in the game.
Peace,
(CS236B--June 5, 1970)
⊗
COMMENT ⊗ Registers 0-7 and 15 are used to simulate MIX's
rA-rX and rJ. Registers 10-13 are work registers.
Register 14 contains the MIX word which is the
present instruction. Register 16 contains the
overflow indicator and the comparison indicator
(bits 0-3) and a program counter (pointing to
the next PDP-10 word to be interpreted) in bits
13-35. Register 17 contains the push-down pointer.
⊗
↓RA ←0
↓R1 ←1
↓R2 ←2
↓R3 ←3
↓R4 ←4
↓R5 ←5
↓R6 ←6
↓RX ←7
↓RJ ←15
↓INSTR ←14
↓FLAGS ←↓PC ←16
↓P ←17
↓OVFLAG ←1B18
↓GFLAG ←1B19
↓EFLAG ←1B20
↓LFLAG ←1B21
↓SIFLAG ←1B22
REL0: ;*RES* RELOCATED ZERO, FOR DEBUGGING
EXTIME: 0 ; EXTIME CONTAINS THE NUMBER OF MIX
; EXECUTE CYCLES SINCE OPERATION
; BEGAN
MC0000: BLOCK =4000 ; SIMULATED MIX WORDS
PDL: BLOCK 40 ; PUSH-DOWN LIST
XALL ;DON'T PRINT TEXT OF MACRO EXPANSIONS
DEFINE ULIST1 {DONEIT←←0} ;*RES* prepare to turn off listing
DEFINE ULIST2 {IFE DONEIT, {DONEIT←←1↔XLIST}} ;*RES* turn it off
; The two macros above are used to control length of macro
; generated code listing. They are used in the following way:
;
; ULIST2 is put in a suitable place in the definition of <macro>
;
; ULIST1
; <macro>
; LIST
SUBTTL MIXLOG - LOG OF ADDITIONS AND CORRECTIONS
COMMENT ⊗ Log of Additions and Corrections by Dick Sweet to MIX Software
--------------------------------------------------------------
Early in the game:
All Much grand old pseudo-opery to control listing size.
MIX000 p. 2 The macros ULIST1 and ULIST2 used above.
MIXIO p. 4 Literal for cr-ff corrected to 6430
MIXIO p. 4 Call to PRNWRD in IOC instr
MIXMON p. 8 Save F in MOD instr, needed by TRACE
MIXMON p. 11 Re-pick up F in MOVE instr
MIXMON p. 11 Inserted PATCH area
MIXAL0 p. 15 Fix SCANA1 to work if fewer than 5 chars after ALF
N.B. at least 1 is still needed (tab or blank)
MIXBUG p. 14 Check left half of entry for special case
MIXBUG p. 14 Put out proper field for IO instr in $E
1/31/72
MIXBUT p. 1 Put in switches for no eject on printer
MIXBUT p. 2 Put in code for above switches
MIXIO p. 3 Put in code for above switches in print routine
MIXBUT p. 1 Switch for listing news file
MIXBUT p. 2 Code for above switch
MIX999 p. 2 Call to news routine at initialization
MIX999 p. 3 News routine
2/1/72
All Started converting files to TVEDIT, page numbers above
will probably no longer be correct
MIXAL0 p. 18 Martin Frost changed SIXMIX entry for "+" to 44
MIXFIL Created file from half of first page of MIXIO so that the
same routine could be used by MIX and MIXAL
MIXFIL p. 2 Made about 5 corrections to get PPN's processed correctly
MIXIO p. 6 Changed GETWRD to ignore nulls since INCRD didn't read SOS
files correctly
MIXAL0.0 Removed FINFO to MIXFIL, inserted ULIST macros
2/3/72
MIXDD A new file, routines to display machine status on Data Disk
consoles similar to III routines put in by Dave Barstow
MIXDPY Changes to make MIXDD work easier. Notably, replace UPGMVM
instrs by MOVEM and doing a UPGIOT every time. Thus, the
correct values can be picked up out of the III buffer.
MIXBUT A new button to rewrite DD screen (<ctrl><form>)
MIX999 p. 3 Check for both kinds of DPY at init
MIX999 p. 3 Change # of glitches in piece of paper (3 for III, 4 for DD)
MIX999 p. 3 Initialize PC to MIX 0 (=MC0000) so initial display of PC
is no longer garbage
MIX999 p. 4 Ask if news desired, first giving user creation date and time
of the NEWS file. Consider using MIX.MSG[2,2] some time for
the news file.
2/4/72
MIXMON p. 9 Removed parens from last 2 entries in M0XCT so that ENTi and
ENNi wouldn't get an ILL MEM REF when they have an efective
address of 0 and an index of 6!
MIXBUG p. 15 Fixed bug that caused program to loop when examining a location
with a negative address field.
MIXBUG Several changes to allow various routines to be used by the
symbolic instruction part of MIXDD
MIXDD p. 3 Whole new routine to display next instruction in symbolic form.
It should probably be in MIXDPY and come out on both DD and
III displays.
MIXERR P. 2 Fixed error routines to:
1. Display PC of error
2. Optionally halt on non-fatal errors
3. Adjust PC on fatal errors to offending instruction
MIXBUT New buttons ERRHALT and ERRGO to control action at non-fatal
errors.
2/7/72
MIX999 p. 3 Initialize PC before calling DDUPD first time now that symbolic
instr is displayed.
MIXBUT p. 3 Corrected SKIP instr in QREWRT so that DD displays could be
rewritten.
MIXBUG p. 11 Changed GETSYM so that if no match, offset is set to value
MIXDD p. 3 Various fixes to symbolic display routines
2/8/72
MIXBUT P. 5 RESCN routine to rescan last TTY line looking for second argument
MIXBUT p. 4 Use RESCN in SETUP and SETPC routines
MIXFIL p. 2 Alternate entry for use with RESCN
MIXIO p. 2 Use RESCN in READ, PUNCH, and PRINT routines
MIXAL0 p. 28 Use RESCN in MIXAL routine
MIXRUN p. 2 Use RESCN in TRACE and TK routines
MIXMLD p. 2 Use RESCN in MLD routine
2/9/72
MIXBUT p. 5 Changed RESCN to just continue reading current line
MIXBUT p. 2 Changed BUTTON routine to do different things with buttons that
could have arguments
2/22/72
MIXDD p. 3 Maximum offset for printing changed from ∞ to 77
MIXDD p. 5 Moved screen down so EX TIME won't remain on screen
MIXBUT p. 3 Changed DISPLAY button to do more reasonable things
MIXBUT p. 4 Fixed initialization of reg 11 in SETPC button
MIXRUN p. 2 Fixed initialization of reg 10 in TK button
2/23/72
MIXIO p. 2 Fixed READ, PUNCH and PRINT buttons to read rest of line in
case file is already open
2/28/72
MIXBUT p. 5 Fixed RESCN to do the right thing if it starts out with a LF
as in the case of the TK button
MIXRUN p. 4 Temporarily put in octal dump for MJH
MIXBUT p. 2 " " " " " " "
3/10/72
MIXRUN p. 3 Completely changed TRACE routine (DORUN) to put out values
in bytewise fashion instead of as 30 bit integers. In the
process, did away with Dave's cute "split up the selected
field" routine to print the contents of the addressed cell.
It would not be difficult now to allow different formats
for recording register values in the trace.
MIXRUN p. 4 Changed DUMP routine to allow dump ranges and variable formats
for the dumped locations.
MIXRUN p. 5 Routines for range request and variable format output used
in the two above changes. One can specify a "mask" by which
the value is to be printed. A mask specifies byte groupings
and whether the group is to be printed or ignored. e.g. the
mask "2(1)11" would cause the (bytewise) number "-102030405"
to be printed as "- 0660405".
MIXBUT p. 4 Changed dump routine (QDUMP) to the following syntax:
DUMP {<range>}{<format>}
Where
<range>::= <number> | <number>:<number>
<format>::= /I | /B | /D | /<mask>
<mask>::= <term> | <mask><term>
<term>::= <visible field> | <invisible field>
<visible field>::= <number>
<invisible field>::= (<number>)
In the range specification, any number > 3999 is considered
to be 3999. In a field specification, the number must be
between 1 and 5. The sum of the field sizes must not
exceed 5. The Instruction, Byte, and Decimal formats
correspond to the following masks:
/I ≡ /2111
/B ≡ /11111
/D ≡ /5
MIXMON p. 2 Changed things so that TRACE shows the register status before
the instruction is executed. This necessitated calling GETM
before going to the instruction routine.
MIXMON Changed all other GETM instructions to MOVE 12,MSPEC
MIXIO Changed all GETM instructions to MOVE 12,MSPEC
3/17/72
MIXIO Noticed that data files created by TV are not read correctly
apparently the first couple of chars of the line are dropped
(a reasonable thing to happen). The problem has not been
thoroughly diagnosed or fixed at this time.
2/9/75 REG Combined several source files to eliminate lengthy command lines
Redefined FINFO as a label, rather than an opdef.
MIXAL1 Down-arrowed definition of P. (formerly file MIXAL0.0)
⊗
SUBTTL MIXDPY - III manipulations
COMMENT ⊗ This page contains the dpy picture apparatus.
⊗
XMAX ←← 777
XMIN ←← -777
YMAX ←← 600
YMIN ←← -200
WIDTH ←← =60
HEIGHT ←← =90
BTWEEN ←← =40
DPYHED: DPYPIC
ENDAD-.
DEFINE LVW (X,Y,M,T)
{ X1 ←← (X)⊗31 ∧ 3777B10
Y1 ←← (Y)⊗16 ∧ 3777B21
X1 ∨ Y1 ∨ M⊗6 ∨ T⊗4 ∨ 6
}
DEFINE LVWBS (X,Y,M,T,B,S)
{ X1 ←← (X)⊗31 ∧ 3777B10
Y1 ←← (Y)⊗16 ∧ 3777B21
X1 ∨ Y1 ∨ B⊗11 ∨ S⊗8 ∨ M⊗6 ∨ T⊗4 ∨ 6
}
DEFINE RETURN (N)
{ LVW N*-=12,-30,0,2
}
DEFINE DPYREG
{ASCID /+ 00 00 00 00 00 /
}
DEFINE DPHREG
{ASCID /+ 000000 0000 /
}
DEFINE DPYDAT
{ASCID /000000000000 /
}
DEFINE DPYAD
{ASCID /0000 /
}
DEFINE DD1 &(A) {↓DDLB&A:}
DEFINE DD2 &(A) {↓DDSZ&A←←.-DDLB&A}
DPYPIC: 0
LVW XMIN,YMAX,1,2
LVW XMAX,YMAX,1,0
LVW XMAX,YMIN,1,0
LVW XMIN,YMIN,1,0
LVW XMIN,YMAX,1,0
LVW BTWEEN,-BTWEEN-HEIGHT,0,2
LVW 0,HEIGHT,0,0
LVW WIDTH/2,-HEIGHT/2,0,0
LVW WIDTH/2,HEIGHT/2,0,0
LVW 0,-HEIGHT,0,0
LVW BTWEEN,0,0,2
LVW 0,HEIGHT,0,0
LVW BTWEEN,-HEIGHT,0,2
LVW WIDTH,HEIGHT,0,0
LVW -WIDTH,0,0,2
LVW WIDTH,-HEIGHT,0,0
LVW XMAX-4*BTWEEN-3*WIDTH,YMAX-BTWEEN-HEIGHT,1,2
LVW 0,HEIGHT,0,0
LVW BTWEEN,0,0,2
LVW WIDTH,0,0,0
LVW 0,-HEIGHT,0,0
LVW -WIDTH,0,0,0
LVW 0,HEIGHT,0,0
LVW WIDTH+BTWEEN,0,0,2
LVW WIDTH,0,0,0
LVW 0,-HEIGHT,0,0
LVW -WIDTH,0,0,0
LVW 0,HEIGHT,0,0
LVW WIDTH+BTWEEN,0,0,2
LVW WIDTH,0,0,0
LVW 0,-HEIGHT,0,0
LVW -WIDTH,0,0,0
LVW WIDTH,HEIGHT/2,0,2
LVW -WIDTH,0,0,0
LVW 0,HEIGHT/2,0,0
LVW XMIN+BTWEEN,250,1,2
DD1(12)
ASCID /rA : /
DPYRA: DPYREG
DD2(12)
RETURN =25
DD1(13)
ASCID /rX : /
DPYRX: DPYREG
DD2(13)
RETURN =25
DD1(14)
ASCID /ri1: /
DPYRI1: DPHREG
DD2(14)
RETURN =25
DD1(15)
ASCID /ri2: /
DPYRI2: DPHREG
DD2(15)
RETURN =25
DD1(16)
ASCID /ri3: /
DPYRI3: DPHREG
DD2(16)
RETURN =25
DD1(17)
ASCID /ri4: /
DPYRI4: DPHREG
DD2(17)
RETURN =25
DD1(20)
ASCID /ri5: /
DPYRI5: DPHREG
DD2(20)
RETURN =25
DD1(21)
ASCID /ri6: /
DPYRI6: DPHREG
DD2(21)
RETURN =25
DD1(11)
ASCID /rJ : /
DPYRJ: DPHREG
DD2(11)
LVW 0,250,1,2
DD1(1)
ASCID /EXECUTE TIME = /
DPYXT: DPYREG
DD2(1)
RETURN =35
DD1(2)
ASCID /PROGRAM COUNTER = /
DPYPC: DPYAD
DD2(2)
RETURN =25
DD1(3)
ASCID /INS: /
DPYIN: DPYREG
DD2(3)
RETURN =25
RETURN 0
DD1(5)
DPYOV: ASCID / OVERFLOW /
DD2(5)
RETURN =15
RETURN 0
DD1(6)
DPYG: ASCID / GREATER /
DD2(6)
RETURN =15
DD1(7)
DPYE: ASCID / → EQUAL/
DD2(7)
RETURN =10
DD1(10)
DPYL: ASCID / LESS /
DD2(10)
ENDAD: XWD DPYPIC, 20
COMMENT ⊗ This section has all the display facilities, including
all the handy-dandy, neat little pictures.
⊗
UPDAD: 0
OPDEF UPDATE [PUSHJ P, .]
SKIPE DDSW ;ARE WE ON A DD?
JRST .+5 ;YES
MOVNI 10, 1
GETLIN 10
SKIPL 10
POPJ P,
INDS: MOVE 10, DPYOFF
TLNE FLAGS, OVFLAG
MOVE 10, DPYON
MOVEM 10, DPYOV
MOVE 10, DPYOFF
TLNE FLAGS, GFLAG
MOVE 10, DPYON
MOVEM 10, DPYG
MOVE 10, DPYOFF
TLNE FLAGS, EFLAG
MOVE 10, DPYON
MOVEM 10, DPYE
MOVE 10, DPYOFF
TLNE FLAGS, LFLAG
MOVE 10, DPYON
MOVEM 10, DPYL
REGS: MOVEI 10, REGLST ; INIT ADDRESS COUNTER
MOVEM 10, UPDAD
SKIPN 10, @UPDAD ; 0 → NO MORE
JRST DATS
MOVE 10, (10) ; 10 ← SOURCE WORD
MOVE 12, [POINT 7, REGBLK] ; POINTER TO DESTINATION BLOCK
MOVE 13, [POINT 3, 10, 5] ; POINTER TO SOURCE
MOVEI 11, "+" ; FIRST DO SIGN BIT
SKIPGE 10
ADDI 11, 2 ; CHANGE TO "-"
IDPB 11, 12
IBP 12 ; SPACE
ILDB 11, 13 ; FIRST DIGIT OF PAIR
ADDI 11, 60
IDPB 11, 12
ILDB 11, 13 ; SECOND DIGIT OF PAIR
ADDI 11, 60
IDPB 11, 12
TLNE 13, 770000 ; ANY MORE PAIRS?
JRST .-10 ; YES
HLRZ 10, @UPDAD ; PREPARE FOR TRANSFER TO DPY AREA
MOVE 11, REGBLK
MOVEM 11, (10) ; NOW DO TRANSFER
AOJ 10,
MOVE 11, REGBLK+1
MOVEM 11, (10)
AOJ 10,
MOVE 11, REGBLK+2
MOVEM 11, (10)
AOJ 10,
MOVE 11, REGBLK+3
MOVEM 11, (10)
AOS UPDAD ; GET NEXT REGISTER
JRST REGS+2
DATS: MOVEI 10, DATLST ; INIT ADDRESS COUNTER
MOVEM 10, UPDAD
SKIPN 10, @UPDAD ; 0 → NO MORE
JRST ADS
MOVE 10, (10) ; 10 ← SOURCE WORD
MOVE 12, [POINT 7, DATBLK] ; POINTER TO DESTINATION BLOCK
MOVE 13, [POINT 3, 10] ; POINTER TO SOURCE
ILDB 11, 13
ADDI 11, 60
IDPB 11, 12
TLNE 13, 770000 ; ANY MORE PAIRS?
JRST .-4 ; YES
HLRZ 10, @UPDAD ; PREPARE FOR TRANSFER TO DPY AREA
MOVE 11, DATBLK
MOVEM 11, (10) ; NOW DO TRANSFER
AOJ 10,
MOVE 11, DATBLK+1
MOVEM 11, (10)
AOJ 10,
MOVE 11, DATBLK+2
MOVEM 11, (10)
AOS UPDAD ; GET NEXT REGISTER
JRST DATS+2
ADS: MOVEI 11, ADLST ; INIT ADDRESS COUNTER
MOVEM 11, UPDAD
SKIPN 11, @UPDAD
JRST BYTES
HRRZ 12, (11) ; 12 ← SOURCE WORD
SUBI 12, MC0000
MOVE 13, [POINT 7, ADBLK] ; POINTER TO DESTINATION BLOCK
MOVEI 10, =1000 ; 10 WILL HOLD DIVISOR
MOVE 11, 12 ; SET UP FOR DIVIDE
IDIV 11, 10 ; GET DIGIT
ADDI 11, 60
IDPB 11, 13
IDIVI 10, =10 ; FIX DIVISOR
JUMPG 10, .-5
HLRZ 10, @UPDAD ; PREPARE FOR TRANSFER TO DYP AREA
MOVE 11, ADBLK
MOVEM 11, (10) ; NOW DO TRANSFER
AOS UPDAD ; GET NEXT REGISTER
JRST ADS+2
BYTES: MOVEI 10, BYTLST ; INIT ADDRESS COUNTER
MOVEM 10, UPDAD
SKIPN 10, @UPDAD ; 0 → NO MORE
JRST DPYOUT ;GO WRITE SCREEN (III OR DD)
HRRZ 11, @UPDAD ; UPMEM ← SOURCE ADDRESS
MOVEM 11, UPMEM
MOVEI 13, BYTDES-BYTLST ; UPBYTE ← GROUP DESCRIPTOR
ADD 13, UPDAD
MOVE 12, (13)
MOVEM 12, UPBYTE
MOVNI 12, 4 ; UPBTIM ← COUNTER FOR GROUP #
MOVEM 12, UPBTIM
MOVE 13, [XWD DPYMDL, DPYWRK] ; SET UP WORK AREA
BLT 13, DPYWRK-DPYMDL+DPYWRK-1
MOVE 13, [POINT 7, DPYWRK] ; AND POINTER
MOVEM 13, UPOINT
MOVEI 13, "+" ; GET SIGN
SKIPGE @UPMEM
MOVEI 13, "-"
IDPB 13, UPOINT
IBP UPOINT
NXTGRP: MOVE 13, UPBYTE ; 13 ← 5*n+i
IMULI 13, 5
ADD 13, UPBTIM
SKIPN DPYPTR+4(13)
JRST ALLDON ; 0 → ALL DONE
LDB 12, DPYPTR+4(13) ; GET BYTE GROUP
MOVE 10, DPYDIV+4(13) ; 10 ← DIVISOR
MOVE 11, 12
IDIV 11, 10
ADDI 11, 60
IDPB 11, UPOINT ; PUT DIGIT INTO WORK AREA
IDIVI 10, =10 ; NEXT DIVISOR
JUMPG 10, .-5 ; BACK FOR MORE DIGITS
IBP UPOINT ; SPACE AFTER GROUP
AOSG UPBTIM ; MORE GROUPS?
JRST NXTGRP ; YES
ALLDON: MOVEI 13, 3
HLRZ 10, @UPDAD
HRRM 10, .+2
MOVE 11, DPYWRK(13)
MOVEM 11, 0(13)
SOJGE 13, .-2
AOS UPDAD
JRST BYTES+2
DPYOUT: SKIPE DDSW ;IS THIS A DATA DISK
JRST DDUPD ;YES, UPDATE SCREEN (DDUPD DOES A POPJ)
UPGIOT DPYHED ;REWRITE III SCREEN
POPJ P,
DPYOFF: ASCID / /
DPYON: ASCID / → /
REGLST: 0
REGBLK: DPYREG
DATLST: 0
DATBLK: DPYDAT
ADLST: XWD DPYPC, PC
0
ADBLK: DPYAD
BYTLST: XWD DPYIN, INSTR
XWD DPYRA, RA
XWD DPYRX, RX
XWD DPYRI1, R1
XWD DPYRI2, R2
XWD DPYRI3, R3
XWD DPYRI4, R4
XWD DPYRI5, R5
XWD DPYRI6, R6
XWD DPYRJ, RJ
XWD DPYXT, EXTIME
0
BYTDES: 7
17
17
2
2
2
2
2
2
2
0
0
UPMEM: 0
UPBTIM: 0
UPOINT: 0
UPBYTE: 0
DPYMDL: ASCID / /
DPYWRK: ASCID / /
QUPDAT: MOVNI 10, 1 ; IS IT A DPY
GETLIN 10
JUMPGE 10, .+3 ; NO → DON'T UPDATE
PGSEL 0 ; PICK PIECE OF GLASS
UPDATE
JRST BUTTON
COMMENT ⊗ If the PDP address of the word to be displayed is
in UPMEM then the following tables can be used to
get the appropriate byte groups for updating the
display.
n = a 4-bit number, where bit k is on if
byte k in the MIX word should begin
a new grouping. (e.g. standard
instruction format is:
n=7 or + AA I F C)
i = the # of the group which you wish to use (1≤i≤5)
DPYPTR+5*n+i-1 is a byte pointer to the right bytes
or 0 if no bytes left
DPYDIv+5*n+i-1 contains the divisor to start finding
the digits with
⊗
ULIST1
DPYPTR: FOR I←0,17
{ULIST2
X1←←X2←←X3←←X4←←X5←←6
Y1←←=11
Y2←←=17
Y3←←=23
Y4←←=29
Y5←←=35
Z←←1
FOR @$ J←3,0,-1
{IFE I∧1⊗J,
{FOR @! K←Z,Z
{X!K←←X!K+6
Y!K←←Y!K+6
}
FOR @! K←Z+1,4
{FOR @% K1←K+1,K+1
{X!K←←X%K1
Y!K←←Y%K1
}
}
}
IFN I∧1⊗J, {Z←←Z+1}
}
FOR @$ J←1,Z
{ POINT X$J, @UPMEM, Y$J
}
FOR J←Z+1,5
{ 0
}
}
LIST
ULIST1
DPYDIV: FOR I←0,17
{ULIST2
X1←←X2←←X3←←X4←←X5←←6
Z←←1
FOR @$ J←3,0,-1
{IFE I∧1⊗J,
{FOR @! K←Z,Z
{X!K←←X!K+6
}
FOR @! K←Z+1,4
{FOR @% K1←K+1,K+1
{X!K←←X%K1
}
}
}
IFN I∧1⊗J, {Z←←Z+1}
}
FOR @$ J←1,5
{D←←1
FOR K←1,X$J/3-1
{D←←=10*D
}
D
}
}
LIST
SUBTTL MIXDD DD manipulation routines
COMMENT ⊗ ROUTINES TO DISPLAY MIX STATUS ON DATA DISK DISPLAYS
For each screen entry, there is a shadow entry kept of the
contents of the screen. When DDUPD is called, only those things which
have changed are rewritten.
⊗
BEGIN DDDPY
T←← 0
A←← 1
B←← 2
C←← 3
D←← 4
E←← 5
F←← 6
NEWMSK←← 16
↑DDUPD: ;UPDATE DD DISPLAY
MOVEM 16,SVREG+16 ;SAVE REGISTERS
MOVEI 16,SVREG
BLT 16,SVREG+15
; Update DD screen ***
spec←15
tac7←←7
tac6←←6
tac5←←5
tac4←←4
tac1←←1
tac2←←2
t←←0
value←←10
movei tac7,lintbl ; First ldb
move tac1,upd0
movem tac1,upd1
movei tac1,topbuf
movem tac1,buftop ; Start at the beginning of the buffer
updlp: skipn tac5,linmod(tac7) ; zero mode means empty line
jrst nxtupd ; Go on to next line
hrrz value,linadr(tac7) ; MIX adr of cell
trne tac5,4000 ; was this a register ?
addi value,svreg-acsave ; since we save registers in a different
; place than MIXBUG does.
pushj p,fetch ; get contents
camn tac6,linval(tac7) ; match ?
jrst nxtupd ; yes, so don't need to touch this line
pushj p,setlb ; set up label again
; [future mod: add space in each ldb for
; the label, saving lots of time.]
ldb tac5,[point 4,linmod(tac7),35] ; get back the mode
push p,tac7 ; save list pointer
pushj p,@modes(tac5) ; call appropriate display routine
pop p,tac7 ; restore pointer
pushj p,endlin
nxtupd: hlrz tac7,linadr(tac7) ; get next link
caie tac7,lintbl ; all the way around ?
jrst updlp ; no so do next line
move tac1,buftop ; get top of buffer
camn tac1,topbuf ; did any lines change ?
popj p, ; no, so don't touch the screen !
setzm (tac1) ; make a "halt" DD instruction
subi tac1,ddbuf-1 ; length of buffer
movem tac1,ddopg+1
upgiot ddopg ; *** write out screen ***
jrst writ4 ; restore acs and leave
NXS2: MOVEI A," "
IDPB A,T ;DEPOSIT 2 BLANKS
IDPB A,T
; DO THE OP CODE
MOVE 7,10 ;GET REL LOC OF INSTR
PUSHJ P,DECIDF ;DECIDE ABOUT F FIELD
MOVE B,@STROP(10) ;GET OP CODE MNEMONIC
MOVEM B,MNEM#
MOVE B,[POINT 7,MNEM]
ILDB A,B
JUMPE A,NXS3 ;COPY UNTIL 0
IDPB A,T
JRST .-3
NXS3: MOVEI A," " ;NOW 2 MORE BLANKS
IDPB A,T
IDPB A,T
; DO THE ADDRESS PART
HLRZ 10,MC0000(7) ;PICK UP ADDR OF INSTR
SKIPL MC0000(7) ;IS IT NEGATIVE
JRST NXS5 ;NO
ANDI 10,7777
TLO 10,400000 ;TURN ON SIGN BIT
PUSHJ P,GETNSM ;LOOK UP IN SYMTAB
JUMPN 4,NXS4 ;EXACT MATCH
MOVEI A,"-" ;WE'LL NEED THIS IN ANY OTHER CASE
IDPB A,T
JUMPN 3,NXS4 ;THERE WAS A ABS VAL MATCH
HRRZ 4,10 ;PUT ABS VAL IN OFFSET SLOT
JRST NXS6 ;GO DO IT
NXS4: PUSHJ P,SYMOUT ;PUT OUT SYMBOLIC
JRST NXS7
NXS5: PUSHJ P,SYMGET ;LOOK UP SYMBOL AND OFFSET
JUMPE 3,NXS6 ;NO SYMBOL
SKIPN 3(3) ;SEE IF VALUE OF SYMBOL IS 0
JRST NXS6 ;DO LIKE RAID, DON'T PRINT IT
CAIG 4,77 ;DON'T PUT OUT AN OFFSET OF GREATER THAN 77
JRST .+3
MOVE 4,10 ;PUT VALUE OF LOC IN REG 4
JRST NXS6 ;PUT THAT VALUE IS DISPLAY
PUSHJ P,SYMOUT ;WRITE SYMBOL
JUMPE 4,NXS7 ;NO OFFSET
MOVEI A,"+"
IDPB A,T ;PUT OUT A +
NXS6: PUSHJ P,NUMOUT ;PUT OUT OFFSET
; DO INDEX FIELD
NXS7: LDB 4,[POINT 6,MC0000(7),23] ;PICK UP INDEX
JUMPE 4,NXS8 ;NO INDEX
MOVEI A,","
IDPB A,T ;PUT OUT A ,
PUSHJ P,NUMOUT ;PUT OUT INDEX VALUE
; DO F FIELD IF NOT THE DEFAULT FOR THE OP CODE
NXS8: ;JUMPN 6,UPD1 ;GO UPDATE
MOVEI A,"("
IDPB A,T
LDB 4,[POINT 6,MC0000(7),29] ;GET FIELD SPEC
PUSHJ P,NUMOUT ;WRITE IT OUT
MOVEI A,")"
IDPB A,T
; JRST UPD1 ;NOW GO WRITE SCREEN
COMMENT ⊗ WRITE OUT THE LABEL WHICH IS A SIXBIT STRING OF UP TO 12 CHARACTERS
IN LOCATIONS 1(3)-2(3). DEPOSIT ASCII CHARACTERS BY POINTER T
⊗
symout: move a,1(3)
movem a,symb
move a,2(3)
movem a,symb+1
move b,[point 6,symb]
ILDB A,B ;GET A CHAR
JUMPE A,cpopj ;QUIT AT 0
ADDI A,40 ;CONVERT TO ASCII
IDPB A,T ;STORE IN OUTPUT BUFFER
JRST .-4
symb: block 3
COMMENT ⊗ WRITE OUT THE NUMBER IN REG 4 IN DECIMAL ⊗
↑↑NUMOUT:IDIVI 4,=10 ;DIVIDE BY TEN
HRLM 5,(P) ;SAVE ON STACK
SKIPE 4 ;IS THAT ALL
PUSHJ P,NUMOUT ;NO
HLRZ 4,(P) ;GET DIGIT OFF STACK
ADDI 4,60 ;CONVERT TO ASCII
IDPB 4,T ;STORE IT
cpopj: POPJ P, ;NEXT DIGIT OR RETURN
↑↑symprt:pUSHJ P,SYMGET ;GET LABEL FOR INSTR
JUMPE 3,NXS1 ;NO SYMBOL
SKIPN 3(3) ;SEE IF VALUE OF SYMBOL IS 0
JRST NXS1 ;DO LIKE RAID, DON'T PRINT IT
CAIG 4,77 ;DON'T PUT OUT AN OFFSET OF GREATER THAN 77
JRST .+3
MOVE 4,10 ;PUT VALUE OF LOC IN REG 4
JRST NXS1 ;PUT THAT VALUE IS DISPLAY
PUSHJ P,SYMOUT ;PUT SYMBOL IN BUFFER
JUMPE 4,cpopj ;NO OFFSET
MOVEI A,"+"
IDPB A,T ;DEPOSIT A +
nxs1: jrst numout
; Subroutine to see if a line needs to be updated
; enter with tac5: mode code
; tac6: MIX word we want displayed
; value: address of this word (relative to mc0000)
; exits with T = a byte pointer to deposit stuff into & label set up,
; or jumps to bugout if no changes need to be made
↑↑setl: move tac7,curtop
setla: hrrz tac4,linadr(tac7) ; Same address ?
came tac4,value
jrst setla1 ; No--try next line
camn tac6,linval(tac7) ; Values match ?
came tac5,linmod(tac7) ; and modes ?
jrst setlb ; nope
pop p,(p) ; yes, so forget it.
jrst bugout
setla1: hlrz tac7,linadr(tac7) ; get next link
came tac7,curtop ; come all the way around ?
jrst setla ; no--go check next line
hrrm value,linadr(tac7)
setlb: movem tac6,linval(tac7) ; update the ldb
movem tac5,linmod(tac7)
move t,buftop ; set up the byte pointer
move tac1,linins(tac7)
movem tac1,@t ; put in DD instruction
aoj t,
hrli t,440700 ; make bp
movei tac1,40 ; first two positions are blank
idpb tac1,t
idpb tac1,t ; for future expansion(eg *s a la RAID?)
trnn tac5,4000 ; Is this a register ?
jrst setlc ; no.
lsh tac5,-4
andi tac5,177 ; get ascii for register name
movei tac1,"r" ; print cute stuff
idpb tac1,t
movei tac1,"I" ; is it an index register ?
caig tac5,"9"
idpb tac1,t ; yes
idpb tac5,t
jrst .+2
setlc: pushj p,symprt ; stuff in label
movei tac5,40
move tac2,buftop
addi tac2,3
hrli tac2,010700 ; last char of buftop+3
idpb tac5,t ; fill out 4 word's worth
came t,tac2
jrst .-2
hlrz tac5,linadr(tac7) ; get adr of next ldb
movem tac5,curtop ; which is where next line may go
popj p,
; Subroutine to set up odd numbered entry in ddbuf
↑↑setbuf:hrrz tac1,t
sub tac1,buftop ; this is the length of the latest entry
movni tac2,-1(tac1) ; make aobjn pointer
hrl tac2,tac2
hrr tac2,buftop
movei tac4,1
orm tac4,1(tac2) ; convert text to DD text
aobjn tac2,.-1
movs tac2,buftop ; start of latest entry
hrr tac2,t ; top of buffer space
addi tac1,-1(tac2) ; last word transfered goes here
blt tac2,(tac1) ; copy latest entry
hrri t,1(tac1) ; new top of buffer space
hrrzm t,buftop
movei tac1,10000
orm tac1,(tac2) ; turn into odd numbered line adr
popj p,
COMMENT ⊗ NOW WRITE ALL INFO TO THE DATA DISK BUFFER ⊗
;PD1: MOVNI A,NDPY ;GET # OF ENTRIES
SKIPA NEWMSK,[0] ;ZERO OUT MASK FOR CHANGED ENTRIES
LKDPY: LSH NEWMSK,1 ;GET PLACE FOR BIT FOR NEXT ENTRY
MOVE B,SIZE+NDPY(A) ;GET (SIZE OF ENTRY)-1
HLRZ C,LOC+NDPY(A) ;GET LOC OF NEW ENTRY
HRRZ D,LOC+NDPY(A) ;GET LOC OF SHADOW ENTRY
HRLI C,B
HRLI D,B
; Now compare entry with shadow entry
CMPR: MOVE T,@C ;PICK UP WORD OF NEW
CAME T,@D ;COMPARE TO SHADOW
JRST NEW1 ;NOT THE SAME
SOJGE B,CMPR ;LOOK AT NEXT WORD
AOJLE A,LKDPY ;NO CHANGE IN ENTRY, LOOK AT NEXT ENTRY
JRST WRIT1 ;THAT'S ALL, GO WRITE EVEN LINES
NEW1: IORI NEWMSK,1 ;TURN ON BIT IN MASK
AOJLE A,LKDPY ;LOOK AT NEXT ENTRY
; At this point, NEWMSK has a bit on for each entry that has changed
; from what it is on the screen. Write even lines of these entries
WRIT1:
JUMPE NEWMSK,WRIT4 ;QUIT IT THERE'S NOTHING TO DO
MOVEM NEWMSK,MSKSAV# ;SAVE MASK
MOVEI A,NDPY ;GET # OF ENTRIES
MOVEI E,DDBUF+1 ;POINT TO DD BUFFER
SKIPA
WRIT1A: LSH NEWMSK,-1 ;GET BIT FOR NEXT ENTRY
JUMPE NEWMSK,WRIT2 ;QUIT IF NO MORE HAVE CHANGED
TRNN NEWMSK,1 ;IS BIT ON FOR THIS ENTRY?
SOJA A,WRIT1A ;NO
MOVE T,DDCODE(A) ;GET DD INSTR
MOVEM T,(E) ;STORE IN BUFFER
MOVEI B,1(E) ;GET LOC OF AVAIL BUFFER
MOVE C,B ;SAVE LOC
HLL B,LOC(A) ;GET LOC OF NEW ENTRY
ADD C,SIZE(A) ;POINT TO LAST LOC OF BLT
BLT B,(C) ;MOVE NEW ENTRY TO BUFFER
ADD E,SIZE(A)
MOVE T,CRLF ;TACK CR-LF ON END OF ENTRY
MOVEM T,2(E)
ADDI E,3 ;MOVE E PAST NEW CODE
SOJGE A,WRIT1A ;NOW DO NEXT ENTRY
; Now write odd lines and move entries to shadows
WRIT2:
MOVE NEWMSK,MSKSAV ;GET MASK
MOVEI A,NDPY ;GET # OF ENTRIES
SKIPA
WRIT2A: LSH NEWMSK,-1 ;GET BIT FOR NEXT ENTRY
JUMPE NEWMSK,WRIT3 ;QUIT IF NO MORE HAVE CHANGED
TRNN NEWMSK,1 ;IS BIT ON FOR THIS ENTRY?
SOJA A,WRIT2A ;NO
MOVE T,DDCODE(A) ;GET DD INSTR
IORI T,10000 ;SPECIFY ODD LINE
MOVEM T,(E) ;STORE IN BUFFER
MOVEI B,1(E) ;GET LOC OF AVAIL BUFFER
MOVE C,B ;SAVE LOC
HLL B,LOC(A) ;GET LOC OF NEW ENTRY
ADD C,SIZE(A) ;POINT TO LAST LOC OF BLT
BLT B,(C) ;MOVE NEW ENTRY TO BUFFER
ADD E,SIZE(A)
MOVE T,CRLF ;TACK CR-LF ON END OF ENTRY
MOVEM T,2(E)
ADDI E,3 ;MOVE E PAST NEW CODE
MOVE B,LOC(A) ;NOW MOVE TO SHADOW
MOVEI C,(B)
ADD C,SIZE(A)
BLT B,(C)
SOJGE A,WRIT2A ;NOW DO NEXT ENTRY
; We are now ready to write the buffer
WRIT3:
SETZM T,(E) ;PUT A 0 AT THE END OF THE BUFFER
SUBI E,DDBUF-1 ;CALCULATE SIZE OF BUFFER
MOVEM E,DDOPG+1
UPGIOT 1,DDOPG ;WRITE SCREEN
; The display is updated, restore registers and return
WRIT4: MOVSI 16,SVREG
BLT 16,16
POPJ P,
SVREG: BLOCK 17 ;REGISTERS SAVED HERE
↑↑DDOPG:DDBUF
0
↑↑CRLF: ASCID /
/
COMMENT ⊗ TABLES USED BY DDUPD ⊗
DD1(4)
ASCID /NEXT INS: / ;BUFFER FOR SYMBOLIC NEXT INSTRUCTION
NXINS: BLOCK 12
DD2(4)
NDPY←←21-1
SIZE: ;CONTAINS (SIZE OF ENTRY)-1
FOR @& A←NDPY+1,1,-1
{DDSZ&A -1
}
MAXBUF←←0 ;COUNTER TO DETERMINE BUFFER SIZE NEEDED
MAXSHA←←0 ;POINTER INTO SHADOW TABLE
LOC: ;CONTAINS XWD <LOC OF ENTRY>,<LOC OF SHADOW>
FOR @& A←NDPY+1,1,-1
{ XWD DDLB&A,SHADOW+MAXSHA
MAXSHA←←MAXSHA+DDSZ&A
MAXBUF←←MAXBUF+DDSZ&A+2
}
A←←344
DDCODE: ;CONTAINS DATA DISK INSTRUCTION FOR ENTRY
REPEAT NDPY+1, {BYTE (8) 2,A⊗-4,A∧17 (3) 3,4,5,4
A←←A-14}
SHADOW: BLOCK MAXSHA+1
↑↑DDBUF:BYTE (8) 46,2,2 (3) 1,3,3,4
↑↑topbuf:BLOCK 2*MAXBUF+2
↑↑curtop:lintbl
↑↑buftop:topbuf
lin←←60 ; first line reserved for (gasp) error messages, etc.
↑↑lintbl:
repeat =15,{
block 2
xwd .+2,-1
byte (8) 2,lin⊗-4,lin∧17 (3) 3,4,5,4
lin←←lin+14}
block 2
xwd lintbl,-1 ; circular list of ldbs
byte (8) 2,lin⊗-4,lin∧17 (3) 3,4,5,4
linmod←←0 ; bits 0-24: byte mask if any
; bits 25-36 output mode
linval←←1 ; last known value
linadr←←2 ; LH: link to next ldb,, RH: adr of this cell rel to mc0000
linins←←3 ; DD display instruction for positioning this line
; DD instruction to position display to first line for messages.
define ddflin {byte (8) 2,44⊗-4,44∧17 (3) 3,4,5,4}
COMMENT ⊗ ROUTINE TO REFRESH WHOLE SCREEN ⊗
↑REWRIT: ;REWRITE WHOLE SCREEN
MOVEM 0,SVREG ;SAVE REGISTER 0
SETZM SHADOW ;ZERO OUT SHADOW REGISTERS
MOVE 0,[XWD SHADOW,SHADOW+1]
BLT 0,SHADOW+MAXSHA
MOVE 0,SVREG
JRST DDUPD ;UPDATE SCREEN
BEND DDDPY
SUBTTL MIXBUT Handle "console buttons"
COMMENT ⊗ This section requests the user to "push a button" and
then acts on that request.
⊗
↓BUTTON:
pushj p,ddupd ; III users can forget it!!!
OUTSTR [ASCIZ ⊗
#⊗] ; PROMPT FOR BUTTON
MOVE 13, [POINT 7, 10] ; INITIALIZE BYTE POINTER
INCHWL 11 ; WAIT FOR LINE
ANDI 11,177 ;*RES* IGNORE CONTROL BITS
CAIN 11,14 ;*RES* IS THIS A FORM FEED
JRST QREWRT ;*RES* YES, REWRITE DD SCREEN
cain 11, 175 ; is it an <alt-mode>
jrst mixbug ; yes → go to the debugger
SKIPA 10, [0] ; CLEAR 10 AND SKIP
BUT0: INCHRW 11 ; GE NEXT CHAR
CAIL 11, "a" ; convert lower to upper
CAILE 11, "z"
SKIPA
SUBI 11, 40
CAIN 11,40 ;*RES* IS IT A BLANK
JRST .+6 ;*RES* YES
CAIN 11, 15 ; C-R → END OF BUTTON
JRST .+4
IDPB 11, 13 ; PUT CHAR INTO 10
TLNE 13, 760000 ; P=1 → 10 IS FULL
JRST BUT0
MOVE 11, BLIST
CAMe 10, BLIST(11) ; THIS BUTTON?
AOBJN 11, .-1 ; NO → IF BUTTONS LEFT, TRY THEM
jumpge 11,BUT1 ;*RES* TRY BUTTONS WITH ARGUMENTS
INCHRW 10 ; WAIT FOR L-F
CAIE 10, 12
JRST .-2
JRST @ALIST(11)
BUT1: MOVE 11,BLIST1 ;*RES* GET POINTER TO BUTTON LIST
CAMe 10,BLIST1(11)
AOBJN 11,.-1
jumpl 11,@alist1(11)
OUTSTR [ASCIZ /??/] ; FUNNY BUTTON
clrbfi
JRST BUTTON
BLIST: XWD -ALIST+BLIST+1, 1
0
ASCII ⊗G⊗
ASCII ⊗GO⊗
ASCII ⊗S⊗
ASCII ⊗START⊗
ASCII ⊗L⊗
ASCII ⊗LOAD⊗
ASCII ⊗C⊗
ASCII ⊗CONT⊗
ASCII ⊗H⊗
ASCII ⊗HALT⊗
ASCII ⊗STEP⊗
ASCII ⊗X⊗
ASCII ⊗D⊗
ASCII ⊗DISP⊗
ASCII ⊗M⊗
ASCII ⊗MEM⊗
ASCII ⊗ZXT⊗
ASCII ⊗ZPC⊗
ASCII ⊗EXIT⊗
ASCII ⊗READX⊗
ASCII ⊗PNCHX⊗
ASCII ⊗PRNTX⊗
ASCII ⊗UPDAT⊗
ASCII ⊗PCMLD⊗
ASCII ⊗TRACX⊗
ASCII ⊗NOEJE⊗ ;*RES*
ASCII ⊗EJECT⊗ ;*RES*
ASCII ⊗NEWS⊗ ;*RES*
ASCII ⊗ERRHA⊗ ;*RES*
ASCII ⊗ERRGO⊗ ;*RES*
ASCII ⊗MJH⊗
ASCII ⊗DUM1⊗ ;*RES* IN CASE NEEDED FOR PATCH
ASCII ⊗DUM2⊗
ALIST: 0
BUTTON+1
QGO
QGO
QSTART
QSTART
QLOAD
QLOAD
QCONT
QCONT
QHALT
QHALT
QSTEP
QSTEP
QDISP
QDISP
QMEM
QMEM
QZXT
QZPC
QEXIT
QREADX
QPNCHX
QPRNTX
QUPDAT
QPCMLD
QRUNX
QNOEJ ;*RES*
QEJEC ;*RES*
QNEW ;*RES*
QERHLT ;*RES*
QERRGO ;*RES*
QMJH
QDUM
QDUM
BLIST1: XWD -ALIST1+BLIST1+1,1
ASCII ⊗READ⊗
ASCII ⊗PUNCH⊗
ASCII ⊗PRINT⊗
ASCII ⊗SETUP⊗
ASCII ⊗MIXLO⊗
ASCII ⊗MLD⊗
ASCII ⊗TRACE⊗
ASCII ⊗TK⊗
ASCII ⊗SETPC⊗
ASCII ⊗MIXAL⊗
ASCII ⊗DUMP⊗
ASCII ⊗DUM3⊗
ASCII ⊗DUM4⊗
ALIST1: 0
QREAD
QPUNCH
QPRINT
QSETUP
QMLD
QMLD
QRUN
QRUNC
QSETPC
MIXAL
QDUMP
QDUM
QDUM
QSTART: SETZB RJ, EXTIME ; EXTIME, RJ ← 0
MOVEI PC, MC0000 ; PC ← MC0000
JRST MIXMN1
QGO: MOVEI INSTR, 2044 ; THIS IS "IN 0(16)"
MOVEI PC, MC0000 ; SET PC TO ZERO
JRST MIXMN2 ; NOW EXECUTE THE "IN"
QLOAD: MOVEI INSTR, 2044 ; THIS IS "IN 0(16)"
TLO FLAGS, SIFLAG ; SET THE SINGLE-INSTRUCTION FLAG
JRST MIXMN2 ; NOW EXECUTE THE "IN"
QCONT: JRST MIXMN1 ; GO RIGHT TO WORK
QHALT: JRST BUTTON ; ESSENTIALLY A NO-OP
QSTEP: TLO FLAGS, SIFLAG ; SET SIFLAG
JRST MIXMN1
QZXT: SETZM EXTIME ; EXTIME ← 0
JRST BUTTON
QZPC: SETZ RJ, ; RJ ← 0
MOVEI PC, MC0000 ; PC ← MC0000
JRST BUTTON
QNOEJ: SETOM NOJECT ;*RES* WRITE OVER PERF ON
JRST BUTTON ;*RES* LPT
QEJEC: SETZM NOJECT ;*RES*
JRST BUTTON ;*RES*
NOJECT: 0
QERHLT: SETOM ERRHLT ;*RES* HALT ON NON-FATAL ERRORS
JRST BUTTON
QERRGO: SETzM ERRHLT ;*RES* CONTINUE ON NON-FATAL ERRS
JRST BUTTON
QREWRT: SKIPE DDSW ;*RES* IS THIS A DATA DISK
PUSHJ P,REWRIT ;*RES* YES, REWRITE SCREEN
JRST BUTTON
QNEW: PUSHJ P,QNEWS ;*RES* WRITE OUT CURRENT NEWS
JRST BUTTON
QMJH: SETOM MJHSW# ;OCTAL DUMPS FOR JO
JRST BUTTON
QDUM: JRST BUTTON ;*RES* DUMMY SWITCHES ARE NO-OPS
QEXIT: CALL [SIXBIT /EXIT/] ; SO LONG UNTIL TOMORROW
QMEM: OUTSTR [ASCIZ ⊗ADDRESS ⊗]
INCHRW 11
CAIN 11, "X"
JRST BUTTON
ANDI 11, 17
IMULI 11, =1000
MOVE 10, 11
INCHRW 11
ANDI 11, 17
IMULI 11, =100
ADD 10, 11
INCHRW 11
ANDI 11, 17
IMULI 11, =10
ADD 10, 11
INCHRW 11
ANDI 11, 17
ADD 10, 11
OUTCHR [":"]
MOVE 10, MC0000(10)
PUSHJ P, PMIX
JRST QMEM
QDISP: OUTSTR [ASCIZ ⊗
DISPLAY:
⊗]
OUTSTR [ASCIZ ⊗ EXTIME=⊗]
MOVE 10, EXTIME
PUSHJ P, OUTD1 ;*RES*
OUTSTR [ASCIZ ⊗
PC =⊗]
MOVEI 10,-MC0000(PC) ;*RES*
PUSHJ P, OUTD1 ;*RES*
OUTSTR [ASCIZ ⊗
RA =⊗]
MOVE 10, RA
PUSHJ P, PMIX
OUTSTR [ASCIZ ⊗ RX =⊗]
MOVE 10, RX
PUSHJ P, PMIX
OUTSTR [ASCIZ ⊗ RJ =⊗]
MOVE 10, RJ
PUSHJ P, OUTD1 ;*RES*
JRST BUTTON
POCT: MOVE 13, [POINT 3, 10]
ILDB 11, 13
ADDI 11, 60
OUTCHR 11
TLNE 13, 770000
JRST .-4
OUTSTR [ASCIZ ⊗
⊗]
POPJ P,
PMIX: MOVEI 11, 53
SKIPGE 10
ADDI 11, 2
OUTCHR 11
MOVE 13, [POINT 3, 10, 5]
OUTCHR [" "]
ILDB 11, 13
ADDI 11, 60
OUTCHR 11
ILDB 11, 13
ADDI 11, 60
OUTCHR 11
TLNE 13, 770000
JRST .-10
OUTSTR [ASCIZ ⊗
⊗]
POPJ P,
QSETUP: SETZ 10,
PUSHJ P,RESCN ;*RES* LOOK FOR A SECOND ARG
MOVE 11,RECHAR ;*RES* FOUND ONE
JRST .+5 ;*RES* RESCN SKIPS 2 IF NO ARG
OUTSTR [ASCIZ /INSTRUCTIONS BETWEEN DISPLAY UPDATES: /]
INCHWL 11
SKIPA
INCHRW 11
CAIN 11, 15
JRST .+5
ANDI 11, 17
IMULI 10, =10
ADD 10, 11
JRST .-6
MOVEM 10, UPD0
INCHRW 10
CAIE 10, 12
JRST .-2
JRST BUTTON
QDUMP: SKIPN RUNC
JRST BUTTON
PUSHJ P,RANGE ;*RES* DETERMINE DUMP RANGE
movei 11, ; zap default
CAIE 10,"/" ;*RES* IS A MODE SPECIFIED?
JRST QDMP1A ;NO
INCHWL 10
CAIN 10,"I" ;INSTRUCTION MODE?
MOVE 11,IMASK
CAIN 10,"B" ;BYTE MODE?
MOVE 11,BMASK
CAIN 10,"D" ;DECIMAL MODE?
MOVE 11,DMASK
JUMPN 11,QDMP1
PUSHJ P,MSPARS ;GET SPECIAL MASK
MOVE 11,MASK
CAIG 13,5 ;IS MASK SIZE OKAY
JRST QDMP1 ;YES
OUTSTR [ASCIZ /DUMP MASK IS MORE THAT 5 BYTES LONG
/]
JRST QBUTN
QDMP1A: MOVE 11,BMASK ; Default mode is 5 bytes
QDMP1: MOVEM 11,DFALTM ;STORE DEFAULT MASK
SKIPA
INCHWL 10
CAIE 10,12
JRST .-2
JRST DUMP ;GO TO THE DUMP
QSETPC: PUSHJ P,RESCN ;*RES* LOOK FOR A SECOND ARG
MOVE 10,RECHAR ;*RES* FOUND ONE
JRST .+3 ;*RES* RESCN SKIPS 2 IF NO ARG
OUTSTR [ASCIZ ⊗NEW VALUE FOR P.C. = ⊗]
INCHWL 10
SKIPA 11, [0]
QSPC1: INCHRW 10
CAIN 10, 15
JRST QSPC2
IMULI 11, =10
SUBI 10, 60
ADD 11, 10
JRST QSPC1
QSPC2: INCHRW 10
ADDI 11, MC0000
MOVE PC, 11
JRST BUTTON
COMMENT ⊗ RESCN routine to scan the rest of the line of TTY input looking an
argument. Call is PUSHJ P,RESCN. On return, the first character of
the second argument is in location RECHAR and subsequent TTY inputs
will get the other characters. If there is no second argument on the
line,the routine skips 2 instructions on return.
⊗
RESCN:
PUSH P,10 ;SAVE REGISTER
RESCN1: INCHRW 10 ;READ A CHAR
CAIN 10,15
JRST RESCN2
CAIN 10,12 ;MAYBE A LF
JRST RESCN3 ;YES, GET OUT OF HERE
CAIN 10,40 ;SKIP OVER ANY BLANKS
JRST RESCN1
; We have read to a non-blank, non-CR character
MOVEM 10,RECHAR ;SAVE THE CHARACTER
POP P,10
POPJ P, ;RETURN
; We found a CR before finding a second argument
RESCN2: INCHRW 10
CAIE 10,12 ;READ LF ALSO
JRST .-2
RESCN3: MOVEI 10,2 ;SET TO SKIP 2 ON RETURN
ADDM 10,-1(P)
POP P,10 ;RESTORE REGISTER
POPJ P,
RECHAR: 0
BEGIN MIXBUG ↔ SUBTTL MIXBUG - Dynamic debugger for MIX machine
COMMENT ⊗
MIXBUG is the dynamic debugger that goes with MIX. It is essentially
a few more buttons. Each of these buttons has <alt-mode> as
the first character of its name. The buttons are as follows:
$B address This sets a breakpoint at address.
$U address This removes the breakpoint at address
$U This removes all breakpoints
$E address This examines and dipslays the contents of address
in symbolic instruction mode.
$ES address This examines the contents of address in symbolic
decimal mode.
$EB address This examines the contents of address in byte mode.
$EA address This examines the contents of address in ALF mode.
$ED address This examines the contents of address in decimal
mode.
$EN address This examines the contents of address in numeric-
instruction mode.
$=S address This evaluates the address and types it (the address
itself) in symbolic form.
$=D address This evaluates the address and types it in decimal
form.
$DW address← w-value This deposits this w-value in this
address.
$DI address← instruction This deposits this instruction in
this address.
$J address This begins execution at this address
$X instruction This causes this instruction to be executed.
$<line-feed> This causes *+1 to be displayed in the same mode
as *
Note: all addresses, instructions, w-values may be
symbolic, using the symbols of the most recently
loaded .MLD file. The special character *
when not used as a multiply operator, means
the address of the currently open location,
if there is one, and the value of the P.C.
if there is no currently open location.
⊗
t←0
tac1←1
tac2←2
tac3←3
tac4←4
tac5←5
tac6←6
tac7←7
value←10
v1←11
scant←12
scnval←13
char←14
spec←←15
spec2←←16
↑acsave: block 17 ; for saving the ac's
numsym: 0 ; 0 if still possibly a number
seqnam: 0 ; will hold the sequence name at various times
0
origin: -1 ; will hold the value of *
comment ⊗ INCHAR is a subroutine to read one char from the TTY and
convert it to sixbit. the char is returned in the acc. CHAR.
if a <c-r> is read, the following <l-f> is also read and
returned as octal 100.
⊗
opdef inchar [pushj p, .]
inchr0: inchwl char ; read a char
SETZM METAF
SETZM CTRLF
TRZE CHAR,200 ; Set control and meta flags appropriately
SETOM CTRLF
TRZE CHAR,400
SETOM METAF
jumpe char, INCHR0 ; ignore <null>
cain char, 11 ; convert <tab>
movei char, " " ; to <space>
cain char, 15 ; ignore <c-r>
jrst inchr0
cain char, 12 ; convert <l-f>
jrst [movei char, 100 ; to octal 100
popj p,] ; and return
trze char, 100 ; convert other chars to sixbit
troa char, 40
trz char, 40
popj p, ; return
CTRLF: 0
METAF: 0
comment ⊗ SCAN is a subroutine to return one input token. the token
is returned in SCANT, its associated value (if it has one)
is returned in SCNVAL, and the first char of the next token
is in CHAR.
the permissable tokens are given below:
⊗
LINE←0 ; end of line
COMMA←1 ; comma
LPAREN←2 ; left-parenthesis
RPAREN←3 ; right-parenthesis
SYM←4 ; identifier or number (associated value is the MIX word for the right thing)
PLUS←5 ; plus
MINUS←6 ; minus
STAR←7 ; asterisk (associated value is value of ORIGIN)
SLASH←10 ; slash
DOWNAR←11 ; double slash
COLON←12 ; colon
WHAT←13 ; identifier not found in symbol table
LEFTAR←14 ; left arrow
SPACE←15 ; space or other delimiter
reg←16 ; αR followed by one of {a,1,2,3,4,5,6,x,j} means appropriate register
OP: 0 ; GETS SET IF CURRENT TOKEN IS A LEGAL MIX OP (OPCODE → V1).
comment ⊗ CHRTAB gives information about the various input chars:
CHRTAB+i= 0 if it is an illegal character
k if k is the token number for it and it isn't special
bits ∨ k if k is the sixbit for the token and bits are special bits:
bit 0 → a letter or a digit
bit 1 → a letter
bit 2 → a LINE or a SLASH
⊗
ULIST1
CHRTAB: for i ← 0,100
{ULIST2
j←←0
ife i-100, {j←← 1b2 ∨ line}
ife i-' ', {j←← space}
ife i-',', {j←← comma}
ife i-'(', {j←← lparen}
ife i-')', {j←← rparen}
ife i-'+', {j←← plus}
ife i-'-', {j←← minus}
ife i-'*', {j←← star}
ife i-':', {j←← colon}
ife i-'←', {j←← leftar}
ife i-'/', {j←← 1b2 ∨ slash}
ifge i-'A', {ifle i-'Z', {j←← 3b1 ∨ i-20}}
ifge i-'0', {ifle i-'9', {j←← 1b0 ∨ i-20}}
j
}
LIST
opdef scan [pushj p, .]
scan00: jumpn char, .+3 ; wait for non-blank character
inchar
JUMPE CHAR,.-1 ; IGNORE SPACES
SETZM OP ; NOT AN OP (YET).
move scnval, origin ; default value of scnval is ORIGIN
SKIPE CTRLF ; CONTROL CHARS ARE SPECIAL
JRST SCAN4
skipn scant, chrtab(char) ; check table
jrst bugerr ; illegal character
tlnn scant, 700000 ; are any of the special bits on
jrst inchr0 ; no → put next char in CHAR
tlze scant, 100000 ; is it LINE or SLASH?
jrst [caie scant, slash ; yes, is it slash?
popj p, ; no → it's line, so return
inchar ; get next char
caie char, '/' ; is next char a slash?
popj p, ; no → return
movei scant, downar ; and compress two slashes into downar
jrst inchr0] ; and finally, return
move tac1, [point 6, seqnam] ; pointer to sequence name
setzm seqnam ; set sequence name to blanks
setzm seqnam+1
movei tac2, =12 ; maximum of 12 chars
setzb scnval, numsym ; scnval starts as zero, numsym shows number
scan1: tlze scant, 200000 ; is it a letter
setom numsym ; yes → we don't have a number
tlz scant, 400000 ; turn off letter-digit bit
sosl tac2 ; one more char in seqnam
idpb char, tac1 ; so put it there
imuli scnval, =10 ; no fix up scnval if number
add scnval, scant
inchar ; get next char
skipn scant, chrtab(char) ; and look at table
jrst bugerr ; illegal character
jumpl scant, scan1 ; if it's a digit or letter, keep the sequence going
movei scant, sym ; not a digit or letter, so we have whole sequence
skipn numsym ; was it a number?
popj p, ; yes → return with right token and value
ldb tac1, [point 8, seqnam, 7] ; hash into symbol table
ldb tac2, [point 8, seqnam, 15] ; by taking first two groups of 8 bits
xor tac1, tac2 ; and XORing them
addi tac1, symtab ; this gives us the actual pointer
skipa ; for the first time through
scan2: hrrz tac1, (tac1) ; get base address of next entry
jumpe tac1, [movei scant, what ; zero → this symbol is not in the table
jrst scan5] ; LOOK & SEE IF IT'S A MIX OP
move tac2, seqnam ; see if this entry is it
came tac2, (tac1) 1 ; do first six chars match?
jrst scan2 ; no → try next entry
move tac2, seqnam+1 ; now try next six chars
came tac2, (tac1) 2 ; do they match?
jrst scan2 ; no → try next entry
move scnval, (tac1) 3 ; yes → this is it so get associated MIX word
scan3: movei scant, sym ; it's a symbol
;SEE IF THE TOKEN IS A VALID MIX OP. IF SO, PUT THE OP CODE IN V1 AND
;SET OP FLAG.
scan5: skipe seqnam+1 ; second part of sequence name blank ?
popj p, ; nope; it can't be an op.
movei tac4, oplist ; no we will find op-code by a binary search
movei tac5, lastop ; tac4 and tac5 contain the lower and upper bounds
inst1: move tac1, tac5 ; get index
add tac1, tac4
lsh tac1, -1 ; divide by two to get average
move tac2, (1) ; get OP for comparison
sub tac2, seqnam
jumpg tac2, lower ; it is lower on the list
jumpl tac2, upper ; it is higher on the list
move v1, gotop-oplist (tac1)
SETOM OP ; SET OP FLAG
popj p,
lower: movni tac5, 1 ; reset upper limit
addb tac5, tac1 ; to index-1
lwr1: caml tac5, tac4 ; lower>upper → error
jrst inst1
popj p, ; it wasn't an op; just return
upper: movei tac4, 1 ; reset lower limit
addb tac4, tac1 ; to index+1
jrst lwr1
; control characters come here
scan4: caie char,'r'
popj p,
pushj p,inchr0 ; get another char
movei scnval,=9
move tac2,[point 6,[sixbit/jx654321a/]]
ildb tac1,tac2
came tac1,char
sojg scnval,.-2
jumple scnval,bugerr ; funny register name
addi tac1,40 ; convert to ascii again
movem tac1,regnm ; and save for output routines
addi scnval,acsave-mc0000-1
cain scnval,acsave-mc0000+=9-1
movei scnval,acsave-mc0000+rj ;for some obscure reason rj isn't
;consequtive with the others.
movei scant,reg
jrst inchr0
↑↑regnm:0
repeat 0,<
regnum: acsave-mc0000+ra ; give addresses in acsave relative to mc0000
acsave-mc0000+r1
acsave-mc0000+r2
acsave-mc0000+r3
acsave-mc0000+r4
acsave-mc0000+r5
acsave-mc0000+r6
acsave-mc0000+rx
acsave-mc0000+rj>; end of repeat 0,
comment ⊗ EXPR is a subroutine to read in and evaluate an expression.
it assumes that the first char of the first token is in CHAR.
it skips on return if a valid expression was found--VALUE
contains the MIX word generated by the expression.
it doesn't skip if a valid expression was not found.
in either case, the next token is in SCANT.
⊗
opdef expr [pushj p, .]
expr00: scan ; get first token
expr0a: setzb value, spec ; we initialize value to zero
cain scant, reg ; if it is a reg
soja spec,[move value,scnval
scan ; get next token to stay in synch
jrst cpopj] ; return
expr01: caie scant, sym ; if it is SYM
cain scant, star ; or *
jrst [move value, scnval ; we start off
jrst expr2]
caie scant, plus ; if it is +
cain scant, minus ; of -
jrst expr1 ; yes → we have a unary-operator
cpopj1: aos (p) ; otherwise it is a valid exprssion (empty)
cpopj: popj p, ; so skip on return
expr1: move tac3,scant ; save operator
scan ; get next token
cain scant, sym ; is it a symbol
jrst .+3 ; yes → we're OK
caie scant, star ; or a *
popj p, ; no → error
cain tac3, minus ; was operator a minus sign?
tlc scnval, 400000 ; yes → complement sign bit of MIX word
move value, scnval ; value is now what we want it to be
expr2: scan ; get next token
cail scant, plus ; is it a binary-operator
caile scant, colon
jrst cpopj1 ; no → we have found our expression
move tac3, scant ; remember what the operator is
expr3: scan ; get next token
cain scant, sym ; is it a symbol
jrst .+3 ; yes → we're OK
caie scant, star ; or *
popj p, ; no → error return
move tac4, value ; save original value
tlze value, 400000 ; convert value to two's complement
movns value
tlze scnval, 400000 ; convert scnval to two's complement
movns scnval
xct binop-plus(tac3) ; do whatever the operation calls for
jumpg value, expr2 ; value less than 0 → it's already in MIX format
jumpe value, [tlne tac4, 400000 ; value=0 → must check sign of first operand
tlo value, 400000 ; first operand < 0 → new value should be also
jrst expr2] ; now we have MIX format
movns value ; value less than 0 → take negative
tlo value, 400000 ; and turn on sign bit
jrst expr2 ; and go back for next operator
binop: add value, scnval ; PLUS → we add the operands
sub value, scnval ; MINUS → we subtract the operands
imul value, scnval ; STAR → we multiply the operands
idiv value, scnval ; SLASH → we divide the operands
pushj p, [setz value+1 ; DOWNAR → special divide
ashc value, -5
div value, scnval
popj p,]
pushj p, [imuli value, =8 ; COLON → usually for fields
add value, scnval
popj p,]
comment ⊗ WVAL is a subroutine to read in and evaluate a w-value.
it assumes that the first char of the first token is in CHAR.
it skips on return if a valid w-value was found--VALUE
contains the MIX word generated by the w-value.
it doesn't skip if a valid w-value was not found.
in either case, the next token is in SCANT.
⊗
opdef wval [pushj p, .]
wval00: setzb tac7,spec ; tac7 will hold w-value while it is being generated
SCAN ; GET FIRST TOKEN
SKIPE OP ; IS IT A MIX OP?
JUMPE CHAR,WVAL4 ; YES, BUT IGNORE UNLESS FOLLOWED BY SPACE
PUSHJ P,EXPR0A
jrst [ jumpe spec,wval2a ; not a register so null expr
popj p,]
JRST WVAL1A
WVAL1: expr ; get an expression
JRST WVAL2A ; COULDN'T SO ALL DONE
wval1a: movei tac6, 5 ; tac6 will hold the f-part
move tac3, value ; save value of expression
cain scant, lparen ; is it a left-paren?
jrst wval3 ; yes → go get f-part
wval2: caile tac6, 5 ; does f-part include sign bit?
jrst .+4 ; no
JUMPGE tac3,.+2 ; yes → test sign of operand
tloa tac7, 400000 ; and use it
tlz tac7, 400000
MOVE TAC6, fpoint(tac6) ; now get other bytes
TDC TAC6,[12,,MC0000≠7]
DPB TAC3,TAC6
cain scant, comma ; comma?
jrst wval1 ; yes → back for next part
WVAL2A: move value, tac7 ; put proper thing into value
JRST CPOPJ1 ; so skip on return
sv3: 0
wval3: movem tac3,sv3 ; expr wipes out tac3
expr ; get expression for f-part
popj p, ; couldn't → error in w-value
move tac6, value ; need to remember value of f-part
caie scant, rparen ; is it right-paren?
popj p, ; no → error in w-value
skipl tac6 ; is it a valid f-part?
caile tac6, 55 ; first test: is it in the right range?
popj p, ; no → error
skipn fpoint(tac6) ; is table entry zero?
popj p, ; yes → error
scan ; get next token after )
move tac3,sv3 ; restore tac3
jrst wval2 ; scan again
; HERE WHEN WE CHANCE UPON A MIX OPCODE FOLLOWED BY A SPACE
; PARSE THE INSTRUCTION.
WVAL4: MOVE TAC7,V1 ; V1 has the opcode
expr ; get expression for address
jrst bugerr ; error
trz value, 770000 ; get rid of bad bits
hrl tac7, value ; put address into assembling MIX word
skipge value ; was sign bit on?
tlo tac7, 400000 ; yes → turn it on here, too
caie scant, comma ; is next token a comma?
jrst inst3 ; no → then we don't have an index field
expr ; get expression for the index field
jrst bugerr ; error
dpb value, [point 6, tac7, 23] ; put index field into MIX rd
inst3: caie scant, lparen ; is next token a left-parenthesis
jrst inst4 ; no → then we don't have a field-field
expr ; expression for field
jrst bugerr ; error
caie scant, rparen ; next token should be right-paren
jrst bugerr ; it ain't
dpb value, [point 6, tac7, 29] ; put field into MIX word
scan ; must get next token after )
inst4: jumpn scant, bugerr ; final token should be LINE
move value, tac7 ; this is the assembled instruction
jrst cpopj1 ; give good return
comment ⊗ FPOINT is a table of byte pointers for depositing things
into tac7. if an entry is zero, then it is not a valid f-part.
the sign byte is not included.
⊗
REPEAT 0,<
fpoint: 44b5
for y←1,5
{point y*6, tac7, y*6+5
}
repeat 2, {0}
for x←1,5
{for y←0,5
{ifge y-x, then {point (y-x+1)*6, tac7, y*6+5
}
ifl y-x, then {0
}
}
repeat 2, {0}
}>; End of repeat 0( this code is duplicated (almost) elsewhere)
comment ⊗ INST is a subroutine to read an instruction.
the MIX word which is the instruction is returned in
VALUE. control is transferred to bugerr if a valid
instruction is not found.
⊗
COMMENT + THIS CODE IS NOW ON PAGES 20-2 AND 22 +
comment ⊗ ADDR is a subroutine to read an expression and see whether
it is a valid address.
it also checks to see that this is the last token in the line.
⊗
opdef addr [pushj p, .]
addr0: inchar ; input a char to start the expr
WVAL ; get the expression
jrst [ jumpe spec,bugerr
jrst addr1] ; register names are legal addresses.
jumpl value, bugerr ; out of range → error
caile value, =3999
jrst bugerr
addr1: movem value, origin ; save address in ORIGIN
popj p, ; return
comment ⊗ ADDRC is a subroutine to read an expression and see whether
it is a valid address.
it also checks to see that it is followed by a left-arrow.
⊗
opdef addrc [pushj p, .]
addrc0: addr ; get a legal address
caie scant,leftar ; left arrow ?
jrst bugerr ; no → error
popj p, ; return
comment ⊗ GETSYM is a subroutine to find a symbolic expression for
a value. only symbols with equivalent MIX words between
0000 and 3999 are considered. GETSYM assumes that VALUE
contains the value to be considered. a pointer to the
best symbol table entry is returned in tac3 (zero if no
symbol was found) and the offset is returned in tac4.
⊗
opdef getsym [pushj p, .]
↑SYMGET: ;*RES* so I can call it from MIXDD
gets0: setz tac3, ; we obviously haven't found a symbol yet
movei tac4, =4000 ; and no symbol could have a worse offset than this
movei tac1, linked ; to start table search
gets1: skipn (tac1) 1 ; is there an entry?
JRST GETS3 ;*RES* no → search is over
skipl tac2, (tac1) 3 ; is equivalent value less than zero?
caile tac2, =3999 ; or greater than 3999?
jrst gets2 ; yes → not a valid symbol
sub tac2, value ; get difference between value and symbl's equivalent
movns tac2 ; take VALUE-SYMBOL
jumpl tac2, gets2 ; don't want a negative offset
caml tac2, tac4 ; is it better than we already have?
jrst gets2 ; no → then don't use it
move tac3, tac1 ; yes → then we should save it
move tac4, tac2
gets2: addi tac1, 4 ; now look at next entry
jrst gets1
GETS3: SKIPN TAC3 ;*RES* IF NO HIT,
MOVE TAC4,VALUE ;*RES* SET OFFSET TO VALUE
POPJ P,
comment ⊗ these are a couple of subroutines to do some outputting:
OUTDEC - output a space followed by the decimal number in VALUE
OUTNAM - output a space followed by the sequence name in VALUE,VALUE+1
⊗
opdef outdec [pushj p, .]
↑outd1: idivi value, =10 ; get digits from right end
hrlm value+1, (p) ; put them on the stack
skipe value ; was that the last digit?
pushj p, outd1 ; no → go back for more
hlrz value, (p) ; get digit off stack
addi value, 60 ; convert to ascii
idpb value,t ; output it
popj p, ; next digit or return
opdef outnam [pushj p, .]
outnm0: move tac4, [point 6, value] ; pointer to chars is in tac4
outnm1: ildb tac5, tac4 ; get a char
jumpe tac5, outnm2 ; blank → end of sequence
addi tac5, 40 ; convert to ascii
idpb tac5,t ; output the char
came tac4, [point 6, value+1, 35] ; was that the 12th char?
jrst outnm1 ; no
outnm2: popj p, ; return
comment ⊗ MIXBUG is the starting address of the command interpreter.
⊗
↑mixbug:
movei p, acsave ; save all ac's except p
blt p, acsave+16
move p, [iowd 40, pdl] ; initialize push-down-pointer
skipge origin ; do we already have an address there?
jrst [hrrz tac1, acsave+pc ; no → then use value of p.c.
subi tac1, mc0000 ; relative to mc0000
movem tac1, origin
jrst .+1]
movei tac1,topbuf
movem tac1,buftop
inchar ; input the first char
cain char, 'E' ; is it an E (sixbit)
jrst examin ; yes → go to examine
cain char, 'D' ; is it a D?
jrst dposit ; yes → go to dposit
cain char, 'B' ; is it a B?
jrst break ; yes
cain char, 'U' ; is it a U?
jrst ubreak ; yes
cain char, 'J' ; how about J?
jrst jumper ; yes
cain char, 'X' ; or X?
jrst xxxx ; yes
cain char, '=' ; =?
jrst equal ; yes
cain char, 100 ; line-feed?
jrst lf ; yes
; none of these → error
bugerr: outstr [asciz /???
/]
↑↑bugout:jumpe scant, .+3 ; wait for LINE
scan
jrst .-2
movsi p, acsave ; restore all ac's
blt p, 16
move p, [iowd 40, pdl] ; restore push-down-pointer
jrst button ; and return to button mode
comment ⊗ EXAMIN is what looks at core locations and displays what it sees.
⊗
examin: inchar ; get type of examin
movei tac5,6 ; 6 legal codes
move tac6,[point 6,[sixbit/ndabs /]]
ildb tac2,tac6
came tac2,char ; match ?
sojg tac5,.-2 ; no.
jumple tac5,bugerr
movem tac5,mode ; save mode
addr ; pick up address
push p,value ; save value
pushj p,fetch ; get contents for setl
exch value,(p) ; get back original value for setl
move tac5,mode ; restore tac5 for setl
jumpe spec,ex1 ; is ths a register ?
move tac2,regnm ; yes, so save reg name for setl
lsh tac2,4
tro tac2,4000 ; and set register code.
tro tac5,(tac2)
ex1: pushj p,setl ; set up display line pointer
pop p,value ; now use new value which may be the address
; of a breakpoint storage cell.
move tac5,mode ; get mode (again)
pushj p,@modes(tac5) ; call appropriate output routine
; Finish up the current line and send it to the DD
bugdis: pushj p,endlin ; fill out word with spaces & add crlf
move tac1,buftop ; top of buffer space
setzm 1(tac1) ; stick in a "halt"
subi tac1,ddbuf-1 ; length of entire buffer
movem tac1,ddopg+1 ; for upgiot uuo
upgiot ddopg ; *** write out new line(s) ***
jrst bugout
↑↑endlin:movei tac1,40
idpb tac1,t ; fill with blanks
camg t,[300700,,0] ; skip if just deposited in bits 0-6
jrst .-2
endl1: move tac1,crlf ; put crlf at end
movem tac1,@t
aoja t,setbuf ; copy entry for odd #ed raster line
mode: 0
↑↑modes:0
es0
es00
eb0
ea0
ed00
en0
; Subroutine to fetch into tac6 the contents of the MIX cell with address
; relative to mc0000 in value.
↑↑fetch:hlro tac6,mc0000(value)
aoje tac6,fetch1 ; jumps if it's breakpointed
move tac6,mc0000(value) ; just normal.
popj p,
fetch1: hrrz tac6,mc0000(value) ; get breakpoint table offset
movei value,bptab+1-mc0000(tac6); kludge up value to fool display subrs.
move tac6,bptab+1(tac6) ; and the instruction we stored.
popj p,
; put out cell in symbolic instruction mode
es0: move tac7, value ; tac7 will index to location
movei tac1,40
idpb tac1,t
PUSHJ P,DECIDF ;*RES* DECIDE WHETHER TO PRINT F
JRST ESI2 ;GO DO IT
COMMENT ⊗ The following routine is called to decide whether the F-field of
the instruction is to be printed. It is called by PUSHJ P,DECIDF,
with the relative instruction counter in register 7. On return, reg
10 contains the op code, reg 11 contains the field and reg 6 is a
flag: zero if field is to be printed, non-zero otherwise. As a nice
side effect, the op code mnemonic is an ASCIZ string at @STROP(10) on
exit.
⊗
↑DECIDF:
ldb value, [point 6, mc0000(tac7), 35] ; get op code
ldb value+1, [point 6, mc0000(tac7), 29] ; and f-field
setom tac6 ; tac6 will know whether we should output the field
hlrz tac2, strop(value) ;*RES* are there special names for different fields?
jumpe tac2, esi1 ; no
cain value, 5 ; is op special?
jrst [caile value+1, 3
setzb value+1, tac6
POPJ P,]
cain value, 6 ; or is it a shift?
jrst [caile value+1, =8
setzb value+1, tac6
POPJ P,]
cain value, =39 ; or is it a jump?
jrst [caile value+1, =12
setzb value+1, tac6
POPJ P,]
caige value, =40 ; or one of these jumps?
jrst esi1
caig value, =47
jrst [caile value+1, =8
setzb value+1, tac6
POPJ P,]
caig value, =55 ; or one of the modifies?
jrst [caile value+1, 4
setzb value+1, tac6
POPJ P,]
esi1: cain value, 0 ; is it a NOP?
jrst [caie value+1, 0
setz tac6,
POPJ P,]
cain value, 7 ; is it a MOVE?
jrst [caie value+1, 1
setz tac6,
POPJ P,]
cain value, =32 ; is it STJ?
jrst [caie value+1, 2
setz tac6,
POPJ P,]
caige value, =56 ; is it one which has (0:5) as standard field?
caig value, =33
jrst [caie value+1, 5
setz tac6,
POPJ P,]
jumpe value+1,.+2 ;*RES* otherwise, it uses (0)
setz tac6,
POPJ P,
stuff5: hrli tac1,440700
movei tac2,5
ildb tac3,tac1
jumpn tac3,.+2
movei tac3,40
idpb tac3,t
sojg tac2,.-4
popj p,
esi2: movei tac1,@strop(value) ; output the op-code
pushj p,stuff5
movei tac1,40
idpb tac1,t
hlrz value, mc0000(tac7) ; get address part
andi value, 7777 ; get good bits
skipge mc0000(tac7) ; is it negative?
tlo value, 400000 ; turn on sign bit
jumpge value, esi23
PUSHJ P,GETNSM ;*RES* FIND NEG SYMBOL
JRST ESI22 ;*RES* GO PRNT IT OUT
COMMENT ⊗ The following routine finds whether a negative address is in the
symbol table in either its negative form or absolute value. It is
called by PUSHJ P,GETNSM with the relative address reg 10. On return,
if there was a match in either case, register 3 contains the symbol
table address. If there was an exact match, reg 4 is non-zero.
Reg 11 is destroyed.
⊗
↑GETNSM:
hrrz value+1, value ; value+1 has absolute value
setzb tac3, tac4 ; we will search for a match
movei tac1, linked ; of value or |value|
esi21: skipn (tac1) 1 ; is there an entry?
POPJ P, ;*RES* no → end of table
camn value, (tac1) 3 ; is this a match?
jrst [move tac3, tac1 ; yes → we will use it
setom tac4 ; to remember it was exact
POPJ P,] ;*RES*
camn value+1, (tac1) 3 ; match of absolute value?
move tac3, tac1 ; yes → remember it
ADDI TAC1,4 ;*RES* POINT TO NEXT ENTRY
jrst esi21 ; and back to table
esi22: jumpn tac4, esi221 ; -1 → exact match
movei tac1,"-"
idpb tac1,t
jumpn tac3, esi221 ;*RES* tac3=0 → no suitable symbol found
HRRZ VALUE,VALUE ;*RES* GET ABSOLUTE VALUE
JRST ESI24 ;*RES* GO WRITE IT
esi221: move value, (tac3) 1 ; output the symbol
move value+1, (tac3) 2
outnam
jrst esi3 ; all done with address field
esi23: getsym ; get a matching symbol
jumpe tac3, esi24 ; no match
caile tac4, =100 ; maximum offset of 100
jrst esi24
move tac2, tac4 ; remember offset
move value, (tac3) 1 ; output name
move value+1, (tac3) 2
outnam
move value, tac2 ; now do the offset
jumpe value, esi3 ; zero → don't type it
movei tac1,"+"
idpb tac1,t
esi24: outdec ; this could be any of several values
esi3: ldb value, [point 6, mc0000(tac7), 23] ; get index field
jumpe value, esi4 ; zero → don't output it
movei tac1,","
idpb tac1,t
getsym ; get a matching symbol
jumpn tac4, [outdec ; not an exact match, so don't use it
jrst esi4]
move value, (tac3) 1 ; output the symbol
move value+1, (tac3) 2
outnam
esi4: jumpn tac6, esi5 ; are we supposed to output the field-field?
movei tac1,"("
idpb tac1,t
ldb value, [point 6, mc0000(tac7), 29] ; get it
getsym ; get a matching symbol
jumpn tac4, [outdec ; not an exact match, so don't use it
jrst esi41]
move value, (tac3) 1 ; output the symbol
move value+1, (tac3) 2
outnam
esi41: movei tac1,")"
idpb tac1,t
esi5: popj p,
eb0: movei tac1, "+" ; assume positive
skipge tac2, mc0000(value) ; are we right?
movei tac1, "-" ; no
idpb tac1,t
move tac1, [point 6, tac2, 5] ; pointer to bytes
eb1: ildb value, tac1 ; get byte
movei tac3,40
idpb tac3,t
outdec ; output the byte
tlne tac1, 770000 ; is it the last byte?
jrst eb1 ; no
popj p, ; yes, we're through
ea0: move tac2, mc0000(value) ; must save pointer
move tac1, [point 6, tac2, 5] ; pointer to chars
ea1: ildb value, tac1 ; get a char
move value, mixasc(value) ; convert to ascii
idpb value,t ; and output it
tlne tac1, 770000 ; is is the last char?
jrst ea1 ; no
popj p, ; yes
es00: movei tac1,40
idpb tac1,t
move value, mc0000(value) ; get value to output
ess0: getsym ; get symbolic expression for it
jumpe tac3, es1 ; tac3=0 → couldn't find a symbol
caile tac4, =100 ; maximum offset of 100
jrst es1
move tac1, tac4 ; save offset
move value, (tac3) 1 ; put sequence into value
move value+1, (tac3) 2 ; and value+1
outnam ; output the name
move value, tac1 ; now get the offset
jumpe value, es2 ; zero offset → don't print any
movei tac1,"+"
idpb tac1,t
es1: outdec ; either the offset or the entire value
es2: popj p, ; all done
ed00: movei tac1,40
idpb tac1,t
move value, mc0000(value) ; get the value to output
ed0: movei tac1, "+" ; assume positive
jumpge value, .+3 ; right!
movei tac1, "-" ; wrong!!
tlz value, 400000 ; turn off sign bit
idpb tac1,t ; output the sign
outdec ; and then the value
popj p, ; all done
en0: movei tac1,40
idpb tac1,t
movei tac1, "+" ; assume positive
skipge tac2, mc0000(value) ; are we right?
movei tac1, "-" ; no
idpb tac1,t ; output the sign
ldb value, [point 12, tac2, 17] ; get address field
outdec ; output it
move tac1, [point 6, tac2, 17] ; pointer to other fields
movei tac3,40
en1: ildb value, tac1 ; get field
idpb tac3,t
outdec ; output it
tlne tac1, 770000 ; last field?
jrst en1 ; no
popj p, ; yes
dposit: addrc ; get address followed by ←
pushj p,fetch ; use fetch to kludge value in
; case we're depositing into a break-
; pointed location.
move spec2, value ; save address to deposit into
wval ; get instruction to put there
jumpe spec,bugerr ; registers may be deposited in.
movem value, mc0000(spec2) ; so put it there
jrst bugout ; all done
comment ⊗ BREAK and UBREAK are the places which handle
Break and Unbreak commands
⊗
break: addr ; get address to set breakpoint
jumpl spec, bugerr ; don't allow register names for breakpoints
addi value, mc0000 ; make it an absolute address
movei tac1, =39 ; is it already in the table
soj tac1,
camn value, bptab(tac1) ; is it this entry?
jrst bugout ; yes → don't put it in again
sojg tac1, .-3 ; check next entry
movei tac1, =39 ; now look for blank place
soj tac1,
skipl bptab(tac1) ; is this entry zero?
sojg tac1, .-2 ; no → try next one
jumpl tac1, [outstr [asciz /too many breakpoints
/] ; tac1<0 → went all the way through table
jrst bugout]
movem value, bptab(tac1) ; now put this address into the table
move spec,(value) ; get original contents
movem spec,bptab+1(tac1) ; save
hrli tac1,-1
movem tac1,(value) ; replace cell with bp flag (this value
; shouldn't happen to MIX programs.)
jrst bugout ; and return
ubreak: inchar ; to check for line-feed
cain char, 100 ; is U followed by <l-f>>
jrst ubr1 ; yes → we delete all breakpoints
addr ; get address to unbreak
jumpl spec, bugerr ; don't allow register names for unbreaks
addi value, mc0000 ; make an absolute address
movei tac1, =39 ; find it in table
soj tac1,
camn value, bptab(tac1) ; this entry?
jrst ubr2
sojg tac1, .-3 ; no → try next
jrst bugerr ; couldn't find it → so what
ubr1: movei tac1, =39 ; want to delete all entries
soj tac1,
skipl spec,bptab(tac1)
pushj p,ubr3
sojg tac1, .-3
jrst bugout ; and return
ubr2: push p,[bugout]
ubr: move spec,bptab(tac1)
ubr3: move value,bptab+1(tac1)
movem value,(spec)
setzm bptab+1(tac1)
setom bptab(tac1)
popj p,
↑bptab: repeat =20, {-1 ↔ 0} ; this has the breakpoints
; first word = address (absolute). second word = contents
comment ⊗ JUMPER is (would you believe) what does the jumping
⊗
jumper: addr ; get address to jump to
jumpl spec, bugerr ; can't jump to a register name
addi value, mc0000 ; make it an absolute address
hrrm value, acsave+pc ; put it in right half of P.C.
movsi p, acsave ; now restore accumulators
blt p, 16
move p, [iowd 40, pdl] ; restore push-down-pointer
jrst mixmn1 ; and resume operations
comment ⊗ XXXX is where we go to execute a particular instruction
⊗
xxxx: inchar ; to start off inst
wval ; get the instruction
jrst bugerr
setzm jbusx ; in case it is JBUS *
movem value, acsave+instr ; to get set to go
movsi p, acsave ; now we must restore the accumulators
blt p, 16
move p, [iowd 40, pdl] ; restore push-down-pointer
tlo flags, siflag ; set single-instruction flag
jrst mixmn2 ; and begin execution
comment ⊗ EQUAL is used to show things in different styles
⊗
equal: inchar ; get descriptive character
cain char, 'd' ; decimal mode
jrst eqd ; yes
cain char, 's' ; symbolic mode
jrst eqs ; yes
jrst bugerr ; neither → error
eqd: addr ; get address to consider
jumpl spec, bugerr ; there are no equivalences for registers
outchr [" "]
jrst ed0 ; now go do it
eqs: addr ; get address to consider
jumpl spec, bugerr ; there are no equivalences for registers
outchr [" "]
jrst ess0 ; now go do it
comment ⊗ LF is where we display the next location
⊗
lf: aos value, origin ; get next location
skipl tac5, mode ; now recall whatever mode we were in
caile tac5, 5 ; within allowable range?
jrst bugerr ; no → error
pushj p,fetch ; get MIX word
pushj p,setl ; get display line
move tac5,mode
pushj p,@modes(tac5)
jrst bugdis
BEND MIXBUG
SUBTTL MIXLOK - I/O interlocking.
COMMENT ⊗ MIXLOK is the section that has the stuff do handle
the i/o interlocking. Basically, there are four
subroutines: RLOCK, WLOCK, RRLOCK, WWLOCK. R and W
assume a memory address (relative to MC0000) in MLOCK and skip
if that address may be Read or Written. RR and LL
assume a range, with first address in the left half
of MLOCK and the last address in the right half, and
skip if every address in that range may be Read or Written.
⊗
MLOCK: 0 ; contains memory location (or range) under consideration
RLOCKT: ; table of devices which lock out a read attempt
CRDLOK: -1
0
0
TINLOK: -1
0
0
0
WLOCKT: ; table of devices which lock out a write attempt
CPNLOK: -1
0
0
PRNLOK: -1
0
0
TOTLOK: -1
0
0
0
OPDEF RLOCK [PUSHJ P, .]
SKIPA 11,[RLOCKT]
OPDEF WLOCK [PUSHJ P, .]
MOVEI 11,WLOCKT
LOCK: MOVE 10,(11) ;first entry is the value of EXTIME when the
;device is ready
CAMG 10,EXTIME ;has this time happened yet?
JRST LOKOK ;yes → this device doesn't lock us out
MOVE 10,MLOCK ;this is the address under consideration
CAML 10,1(11) ;does it come before first address in busy-range
CAMLE 10,2(11) ;or after the last?
JRST LOKOK ;yes → then we aren't locked out
POPJ P, ;no → this device won't let us use this address
LOKOK: ADDI 11,3 ;go to next device in table
SKIPE (11) ;zero → no more devices
JRST LOCK ;go back for next device
AOS (P) ;no more devices → we can use this address
POPJ P, ;so skip on return
OPDEF RRLOCK [PUSHJ P, .]
SKIPA 11, [RLOCKT]
OPDEF WWLOCK [PUSHJ P, .]
MOVEI 11, WLOCKT
LLOCK: MOVE 10,(11) ;check on EXTIME for this device
CAMG 10,EXTIME
JRST LLOKOK ;device isn't busy
HLRZ 10,MLOCK ;check first address in range
CAML 10,2(11) ;is it higher than last locked-out address?
JRST LLOKOK ;yes → we're OK
HRRZ 10,MLOCK ;check last address in range
CAMG 10,1(11) ;is it lower than last locked-out address?
JRST LLOKOK ;yes → we're OK
POPJ P, ;no → some address in range is locked out
LLOKOK: ADDI 11,3 ;check next device
SKIPE (11) ;zero → no devices left
JRST LLOCK ;go back and check this device
AOS (P) ;no devices left → we can use this range
POPJ P, ;so skip on return
SUBTTL MIXMON - Central interpreter/monitor
;MIXMON is the central interpreter for MIX instruction words.
↑↑UPD0: 1
↑↑UPD1: 1
MIXMON: SOSn UPD1
pushj p,ddupd ; update DDs
HLLZS 10, ERRORC ; check on too many errors
; TLNE 10, 200
; JRST [OUTSTR [ASCIZ ⊗
;JOB HALTED, TOO MANY ERRORS#⊗]
; JRST HLT]
INSKIP ; ANY INPUT FROM TTY → BACK TO BUTTON
TLZE FLAGS, SIFLAG ; SIFLAG → BACK TO BUTTON
JRST BUTTON ; RETURN CONTROL TO USER
MIXMN1: HRRZ 10, PC ; PC>3999 → ERROR
CAIL 10, MC0000
CAILE 10, MC0000+(=3999)
JRST ZMOVER
SUBI 10, MC0000 ; save present value of PC
MOVEM 10, ISPEC
SETZM JBUSX ; zero out JBUSX in case this is JBUS *
MOVEM 10, MLOCK ; now test for Read-interlock
RLOCK
JRST ZPCLOK ; error
MOVE INSTR,@PC ; GET INSTRUCTION WORD
hlro 10,instr
aoje 10,mixbrk ; breakpoints have -1 in their LH, which
; shouldn't occur in normal MIX code
mixbr2: AOJ PC, ; INCREMENT PROGRAM COUNTER
MIXMN2:
LDB 10,[POINT 6,INSTR,35] ;*RES* GET OP CODE
SETZM MSPEC ;ZERO OUT SAVED EFFECTIVE ADDRESS
CAIE 10,5 ;IS IT A SPECIAL INSTR WITH NO ADDRESS
PUSHJ P,MGET ; NO, GET EFECTIVE ADDRESS
SKIPE RUNC ; RUNC = 0 → no RUN file
PUSHJ P, DORUN
AOS EXTIME ; ONE MORE EXECUTE CYCLE
MOVE 13, INSTR ; SET 13 TO OP-CODE
ANDI 13, 77
JRST @OPLST(13) ; GO TO INSTRUCTION AREA
mixbrk: camn instr,brkflg ; same bp twice in a row ?
jrst mixbr1 ; yes → user typed continue
movem instr,brkflg ; no. set up flag.
hrrzi 10,-mc0000(pc)
outstr [asciz/Breakpoint at /]
pushj p,typdec
outstr crlf
jrst button
mixbr1: move instr,bptab+1(instr) ; pick up original instruction
setzm brkflg ; zap flag
jrst mixbr2 ; and continue.
brkflg: 0
typdec: idivi 10,12
jumpe 10,.+4
hrlm 11,(p)
pushj p,.-3
hlrz 11,(p)
iori 11,60
outchr 11
popj p,
OPLST: NOP
0+ADD
0+SUB
0+MUL
0+DIV
SPEC
SHIFTS
0+MOVE
LDA
LD1
LD2
LD3
LD4
LD5
LD6
LDX
LDAN
LD1N
LD2N
LD3N
LD4N
LD5N
LD6N
LDXN
STA
ST1
ST2
ST3
ST4
ST5
ST6
STX
STJ
STZ
JBUS
IOC
0+IN
0+OUT
JRED
JUMPS
JA
J1
J2
J3
J4
J5
J6
JX
MODA
MOD1
MOD2
MOD3
MOD4
MOD5
MOD6
MODX
CMPA
CMP1
CMP2
CMP3
CMP4
CMP5
CMP6
CMPX
COMMENT ⊗ Field specification:
if M is in register 12
F-byte is in register 11
then "FPOINT(11)" is a byte pointer
to the appropriate byte(s)
in the core position addressed
by M. Sign byte not included.
0 → illegal F-byte.
⊗
↓FPOINT: 44B5
FOR Y←1,5
{POINT Y*6, MC0000(12), Y*6+5
}
REPEAT 2, {0}
FOR X←1,5
{FOR Y←0,5
{IFGE Y-X, THEN
{POINT (Y-X+1)*6, MC0000(12), Y*6+5
}
IFL Y-X, THEN
{0
}
}
REPEAT 2, {0}
}
REPEAT 20, {0}
COMMENT ⊗ Memory specification:
this subroutine assumes present instruction
in INSTR and puts M into register 12--
⊗
OPDEF GETM [PUSHJ P,.]
MGET:
LDB 12, [POINT 6, INSTR, 23] ; GET INDEX-BYTE
jumpl 12,.+2 ; INDEX<0 → ERROR
CAILE 12, 6 ; INDEX>6 → ERROR
PUSHJ P, YINDEX
jumpe 12,.+2 ; INDEX=0 → NO INDEXING
MOVE 12, (12) ; INDEX≠0 → GET INDEX REGISTER
TLZE 12, 400000 ; SIGN=0 → SKIP
MOVN 12,12 ; SIGN=1 → NEGATE IT
HLRZ 11, INSTR ; GET ADDRESS-BYTES
TRZE 11, 400000 ; SIGN=0 → SKIP
MOVN 11,11 ; SIGN=1 → NEGATE IT
ADD 12, 11 ; M ← AA+(I)
MOVEM 12, MSPEC ; save M
POPJ P,
OPDEF GETF [PUSHJ P, .]
LDB 11, [POINT 6, INSTR, 29]
SKIPN FPOINT(11)
PUSHJ P, YFIELD
MOVEM 11, SAVEF
POPJ P,
OPDEF TESTR [PUSHJ P, .]
JUMPE 13, .+2
CAILE 13, 6
POPJ P,
TDZE 10, [XWD 7777,770000]
JRST YIREG
POPJ P,
OPDEF TESTM [PUSHJ P, .]
jumpl 12,.+2
CAILE 12, =3999
PUSHJ P, YMOVER
POPJ P,
COMMENT ⊗ "Load" instructions.
⊗
LDA: LD1: LD2: LD3: LD4: LD5: LD6: LDX:
LDAN: LD1N: LD2N: LD3N: LD4N: LD5N: LD6N: LDXN:
MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Read-interlock
RLOCK
JRST ZRLOCK ; error
GETF
LDB 10, FPOINT(11) ; GET FIELD FROM MEMORY
CAILE 11, 5 ; F≤5 → GET SIGN
JRST .+3
SKIPGE MC0000(12) ; MC0000(12)≥0 → SIGN=+
tlo 10, (1B0) ; SIGN ← -
CAILE 13, 17 ; OP-CODE>15 → "LDN"
TLC 10, 400000 ; CHANGE SIGN
ANDI 13, 7 ; 13 ← REGISTER TO BE LOADED
TESTR
MOVEM 10, (13) ; LOAD REGISTER FROM 10
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
COMMENT ⊗ "Store" instructions.
⊗
STA: ST1: ST2: ST3: ST4: ST5: ST6: STX:
MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Write-interlock
WLOCK
JRST ZWLOCK ; error
GETF
ANDI 13, 7 ; 13 ← REGISTER TO BE STORED
MOVE 10, (13) ; STORE REGISTER TO 10
TESTR
DPB 10, FPOINT(11) ; STORE FIELD INTO MEMORY
CAILE 11, 5 ; F≤5 → STORE SIGN-BYTE
JRST .+3
LDB 10, [POINT 6, (13), 5] ; GET SIGN FROM REGISTER
DPB 10, [POINT 6, MC0000(12), 5] ; STORE SIGN
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
STJ: MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Write-interlock
WLOCK
JRST ZWLOCK ; error
GETF
ANDI 13, 7 ; 13 ← REGISTER TO BE STORED
SETZ 10, ; CLEAR 10 IN PREPARATION
DPB RJ, FPOINT(11) ; STORE FIELD INTO MEMORY
CAIG 11, 5 ; F≤5 → STORE SIGN-BYTE
DPB 10, [POINT 6, MC0000(12), 5] ; STORE SIGN
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
STZ: MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Write-interlock
WLOCK
JRST ZWLOCK ; error
GETF
ANDI 13, 7 ; 13 ← REGISTER TO BE STORED
SETZ 10, ; CLEAR 10 IN PREPARATION
DPB 10, FPOINT(11) ; STORE FIELD INTO MEMORY
CAIG 11, 5 ; F≤5 → STORE SIGN-BYTE
DPB 10, [POINT 6, MC0000(12), 5] ; STORE SIGN
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
COMMENT ⊗ "Arithmetic" instructions.
⊗
ADD: SUB:
MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Read-interlock
RLOCK
JRST ZRLOCK ; error
GETF
LDB 10, FPOINT(11) ; GET FIELD FROM MEMORY
CAILE 11, 5 ; F≤5 → GET SIGN
JRST .+3
SKIPGE MC0000(12) ; MC0000(12)≥0 → SIGN=+
MOVNS 10 ; USE TWO'S COMPLEMENT FORM
CAILE 13, 1 ; OP-CODE≥1 → "SUB"
MOVNS 10
MOVE 11, RA ; SET UP 11 TO WORK
TLZE 11, 400000 ; SIGN≠0 → NEGATE 11
MOVNS 11
ADD 11, 10 ; ADD
JUMPGE 11, .+3 ; 11≥0 → OK
MOVNS 11 ; 11<0 → FIX SIGN
tlo 11,400000
TLZE 11, 370000 ; ANY OVERFLOW?
TLO FLAGS, OVFLAG ; YES → SET OVFLAG
JUMPN 11, .+3 ; 11=0 ∧ A<0 → CHANGE 11 TO -0
JUMPGE RA, .+2
movsi 11,400000
MOVE RA, 11 ; RESULTS TO REGISTER A
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
MUL: MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Read-interlock
RLOCK
JRST ZRLOCK ; error
GETF
LDB 10, FPOINT(11) ; GET FIELD FROM MEMORY
CAILE 11, 5 ; F≤5 → GET SIGN
JRST .+3 ; USE +
SKIPGE MC0000(12) ; MC0000≥0 → SIGN=+
TLOA 12, 400000 ; SIGN=- → MAKE 12 NEGATIVE
SETZ 12, ; SIGN=+ → MAKE 12 ZERO
MOVE 11, RA ; SET UP 11 TO WORK
TLZE 11, 400000 ; SIGN=- → CHANGE SIGN OF 12
TLC 12, 400000
MUL 10, 11 ; MULTIPLY
LDB RX, [POINT 30, 11, 35] ; NUMERIC BITS INTO RX, CLEAR SIGN
ASHC 10, 5 ; SHIFT SO RIGHT BITS IN 10
LDB RA, [POINT 30, 10, 35] ; NUMERIC BITS INTO RA, CLEAR SIGN
JUMPGE 12, .+3 ; 12≥0 → SIGN OF RESULT IS +
TLO RX, 400000 ; SIGNS OF RX, RA ARE -
TLO RA, 400000
MOVEI 10, 11 ; NINE MORE EXECUTE CYCLES
ADDM 10, EXTIME
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
DIV: MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Read-interlock
RLOCK
JRST ZRLOCK ; error
GETF
LDB 13, FPOINT(11) ; GET FIELD FROM MEMORY
SKIPGE 10, RA ; test sign of RA
TLO 12, 600000 ; reset sign bits in 12
CAILE 11, 5 ; F≤5 → use sign
JRST .+3
SKIPGE MC0000(12) ; if positive, no change
TLC 12, 400000 ; negative → change sign of RA
CAML 10, 13 ; |RA|≥|V| → OVERFLOW
TLO FLAGS, OVFLAG
DPB RX, [POINT 30, 11, 30] ; SET UP 11 FOR LOW-ORDER BITS
ASHC 10, -5 ; SHIFT INTO RIGHT POSITION FOR DIV
DIV 10, 13 ; DIVIDE
TLNE 12, 400000 ; CHECK QUOTIENT SIGN BIT
TLO 10, 400000
TLNE 12, 200000 ; CHECK REMAINDER SIGN BIT
TLO 11, 400000
MOVE RA, 10 ; RA ← QUOTIENT
MOVE RX, 11 ; RX ← REMAINDER
MOVEI 10, 13 ; ELEVEN MORE EXECUTE CYCLES
ADDM 10, EXTIME
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
COMMENT ⊗ "Address transfer" insructions
⊗
MODA: MOD1: MOD2: MOD3: MOD4: MOD5: MOD6: MODX:
MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
LDB 11, [POINT 6, INSTR, 29]
MOVEM 11,SAVEF ;*RES* SAVE FOR TRACE ROUTINE
CAIG 11, 3
SKIPGE 11
PUSHJ P, YFIELD ; ILLEGAL F-FIELD
ANDI 13, 7 ; 13 ← REGISTER TO BE MODIFIED
MOVE 10, (13) ; 10 ← SET UP 10 TO WORK
TLZE 10, 400000 ; SIGN≠0 → NEGATE 10
MOVNS 10 ; USE TWO'S COMPLEMENT FORM
XCT MODXCT(11) ; PERFORM APPROPRIATE OPERATION
JUMPGE 10, .+3 ; 10≥0 → OK
MOVNS 10 ; 10<0 → FIX SIGN
tlo 10,400000
TLZE 10, 370000 ; ANY OVERFLOW?
TLO FLAGS, OVFLAG ; YES → SET FLAG
JUMPN 10, .+3 ; SPECIAL CONDITIONS
XCT M0XCT(11)
movsi 10,400000 ; → CHANGE 10 TO -0
TESTR
MOVEM 10, (13) ; RESULTS TO REG
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
MODXCT: ADD 10, 12 ; F=0 → INC...
SUB 10, 12 ; F=1 → DEC...
MOVE 10, 12 ; F=2 → ENT...
MOVN 10, 12 ; F=3 → ENN...
M0XCT: SKIPGE (13) ; F=0 → USE SIGN OF REG
SKIPGE (13) ; F=1 → USE SIGN OF REG
SKIPGE INSTR ; F=2 → USE SIGN OF INSTR
SKIPGE INSTR ; F=3 → USE SIGN OF INSTR
COMMENT ⊗ "Comparison" instructions.
⊗
CMPA: CMP1: CMP2: CMP3: CMP4: CMP5: CMP6: CMPX:
MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
MOVEM 12, MLOCK ; test for Read-interlock
RLOCK
JRST ZRLOCK ; error
GETF
LDB 10, FPOINT(11) ; GET FIELD FROM MEMORY
CAILE 11, 5 ; F≤5 → GET SIGN
JRST .+3
SKIPGE MC0000(12) ; MC0000(12)≥0 → SIGN=+
MOVNS 10 ; USE TWO'S COMPLEMENT FORM
ANDI 13, 7 ; 13 ← REGISTER TO COMPARE
MOVE 12, FPOINT(11) ; PUT FIELD-BYTE POINTER INTO 12
TDC 12, [1000000+MC0000] ; POINTER ADDRESS ← "(13)"
COMMENT ⊗ THIS (↑) CLEVERNESS IS DUE TO DAN SWINEHART ⊗
LDB 12, 12 ; GET FIELD FROM REGISTER SHOWN IN 13
CAILE 11, 5 ; F≤5 → GET SIGN
JRST .+3
SKIPGE (13) ; (13)≥0 → SIGN=+
MOVNS 12
SUB 12, 10 ; SUBTRACT TO GET COMPARE RESULT
TLZ FLAGS, GFLAG∨EFLAG∨LFLAG ; ZERO COMPARISON FLAGS
JUMPLE 12, .+3 ; ≤ → MOVE ON
TLO FLAGS, GFLAG ; > → SET FLAG
JRST .+4 ; DONE
JUMPL 12, .+2 ; < → MOVE ON
TLOA FLAGS, EFLAG ; = → SET FLAG, SKIP
TLO FLAGS, LFLAG ; < → SET FLAG
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
COMMENT ⊗ "Jump" instructions.
⊗
JUMPS: MOVE 12,MSPEC
TESTM
LDB 11, [POINT 6, INSTR, 29] ; GET FIELD-BYTE
MOVEM 11, SAVEF
CAILE 11, 11 ; F>9 → ERROR
PUSHJ P, Y2FIEL
MOVE 11, SAVEF
XCT JMPXCT(11) ; PERFORM APPROPRIATE TEST
JRST MIXMON ; THERE WILL BE NO JUMP
JMP: HRRZ RJ, PC ; RJ ← PC-MC0000
SUBI RJ, MC0000
JSJ: JUMPL 12, ZMOVER ; 12<0 → ERROR
; (12>3999 WILL BE FOUND LATER)
ADDI 12, MC0000 ; PC ← M+MC0000
HRR PC, 12
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
JMPXCT: JRST JMP ; F=0 → JMP
JRST JSJ ; F=1 → JSJ
TLZN FLAGS, OVFLAG ; F=2 → JOV
TLZE FLAGS, OVFLAG ; F=3 → JNOV
TLNN FLAGS, LFLAG ; F=4 → JL
TLNN FLAGS, EFLAG ; F=5 → JE
TLNN FLAGS, GFLAG ; F=6 → JG
TLNN FLAGS, GFLAG∨EFLAG ; F=7 → JGE
TLNN FLAGS, GFLAG∨LFLAG ; F=8 → JNE
TLNN FLAGS, LFLAG∨EFLAG ; F=9 → JLE
JA: J1: J2: J3: J4: J5: J6: JX:
MOVE 12,MSPEC
TESTM
LDB 11, [POINT 6, INSTR, 29] ; GET FIELD-BYTE
MOVEM 11, SAVEF
CAILE 11, 7 ; F>7 → ERROR
PUSHJ P, Y2FIEL
MOVE 11, SAVEF
ANDI 13, 7 ; 13 ← REGISTER TO TEST
MOVE 10, (13) ; SET UP 10 TO WORK
TLC 10, 400000 ; CHECK FOR -0
JUMPE 10, .+2 ; NOT -0 SO RECOMPLEMENT
TLC 10, 400000
XCT JXCT(11) ; TO MIXMON IF TEST FAILS
JRST JMP ; PERFORM THE JUMP
JRST MIXMON
JXCT: JUMPGE 10, MIXMON ; F=0 → J.N
JUMPN 10, MIXMON ; F=1 → J.Z
JUMPLE 10, MIXMON ; F=2 → J.P
JUMPL 10, MIXMON ; F=3 → J.NN
JUMPE 10, MIXMON ; F=4 → J.NZ
JUMPG 10, MIXMON ; F=5 → J.NP
TRNN 10, 1 ; F=6 → J.E
TRNE 10, 1 ; F=7 → J.O
COMMENT ⊗ Miscellaneous operators.
⊗
MOVE: MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
TESTM
LDB 11, [POINT 6, INSTR, 29] ; GET FIELD-BYTE
MOVEM 11, SAVEF
JUMPE 11, MIXMON ; F=0 → LIKE A NOP
HRLM 12, MLOCK ; test for read-interlock-range
HRRM 12, MLOCK
ADDM 11, MLOCK
RRLOCK
JRST ZRLOCK
MOVE 11,SAVEF ;*RES* RRLOCK CLOBBERS 11
HRLM R1, MLOCK ; test for write-interlock-range
HRRM R1, MLOCK
ADDM 11, MLOCK
WWLOCK
JRST ZWLOCK
MOVE 11,SAVEF ;*RES* WWLOCK CLOBBERS 11
MOVE 10, R1 ; COMPUTE ADDRESS OF
ADD 10, 11 ; FINAL DESTINATION
SUBI 10, 1
JUMPL 10, ZMOVER ; 10<0 → ERROR
CAILE 10, =3999 ; 10>3999 → ERROR
JRST ZMOVER
JUMPL R1, ZMOVER ; R1<0 → ERROR
MOVE 13, R1 ; 13 WILL HOLD BLT POINTER
HRL 13, 12 ; SOURCE ADDRESS IS M
ADD 13, [XWD MC0000, MC0000] ; RELOCATION (SORT OF)
BLT 13, MC0000(10) ; PERFORM MOVE OPERATION
ADD R1, 11 ; R1 ← R1+F
LSH 11, 1 ; 2*F MORE EXECUTE CYCLES
ADDM 11, EXTIME
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
SHIFTS: LDB 13, [POINT 6, INSTR, 29] ; GET FIELD-BYTE
MOVEM 13, SAVEF
CAIL 13, 0 ; F<0 → ERROR
CAILE 13, 7 ; F>7 → ERROR
PUSHJ P, Y2FIEL
MOVE 13, SAVEF
MOVE 12,MSPEC ; GET MEMORY SPECIFICATION
JUMPL 12, ZMOVER ; 12<0 → ERROR
TRNE 13, 1 ; 13 ODD → SHIFT RIGHT
MOVNS 12 ; SO NEGATE FACTOR
IMULI 12, 6 ; 1 BYTE = 6 BITS
CAILE 13, 1 ; F=0,1 → SLA,SRA
JRST SAX
MOVE 10, RA ; SET UP 10 TO WORK
TLZ 10, 400000 ; IGNORE SIGN
LSH 10, (12) ; PERFORM SHIFT
DPB 10, [POINT 30, RA, 35] ; PUT BACK SHIFTED BYTES
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
SAX: MOVE 10, RA ; SET UP 10, 11 TO WORK
MOVE 11, RX
TLZ 10, 400000 ; IGNORE SIGN
LSH 11, 6 ; CONCATENATE MEANINGFUL BYTES
CAIGE 13, 6 ; F=6,7 → SRB,SLB
JRST .+3 ; OTHERWISE
IDIVI 12, 6 ; SO CHANGE BACK TO BITS
JRST .+3
CAILE 13, 3 ; F=2,3 → SLAX,SRAX
JRST SC
LSHC 10, (12) ; PERFORM SHIFT
LSH 11, -6 ; BYTES TO NORMAL POSITIONS
DPB 10, [POINT 30, RA, 35] ; PUT BACK SHIFTED BYTES
DPB 11, [POINT 30, RX, 35]
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
SC: ADDI 12, =30000 ; MAKE 12>0 SO CAN USE
IDIVI 12, =60 ; MOD(10)
ROTC 10, (13) ; PERFORM SHIFT
HRRZ 12, 13 ; 6 BITS = 1 BYTE
IDIVI 12, 6
HRR RX, 12 ; USE RX FOR INDEXING
MOVE 12, 10 ; 12,13 USED TO SAVE BYTES
MOVE 13, 11 ; WHICH ARE CORRECT
AND 12, ROTA(RX)
AND 13, ROTX(RX)
ROTC 10, 14 ; ROTATE TO GET REST OF GOOD BYTES
ANDCM 10, ROTA(RX) ; MASK OUT BAD BYTES
ANDCM 11, ROTX(RX)
OR 10, 12 ; PUT GOOD PARTS TOGETHER
OR 11, 13
LSH 11, -6 ; BYTES TO NORMAL POSITIONS
DPB 10, [POINT 30, RA, 35] ; PUT BACK SHIFTED BYTES
DPB 11, [POINT 30, RX, 35]
AOS EXTIME ; ONE MORE EXECUTE CYCLE
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
ROTA: XWD 7777,777777 ; MASKING TABLES FOR SLC AND SRC
XWD 7777,777777
XWD 7777,777777
XWD 7777,777777
XWD 7777,777777
XWD 7777,777777
XWD 7777,777700
XWD 7777,770000
XWD 7777,000000
XWD 7700,000000
ROTX: XWD 777777,777700
XWD 777777,770000
XWD 777777,000000
XWD 777700,000000
XWD 770000,000000
XWD 000000,000000
XWD 000000,000000
XWD 000000,000000
XWD 000000,000000
XWD 000000,000000
NOP: JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
SPEC: LDB 12, [POINT 6, INSTR, 29] ; GET FIELD-BYTE
MOVEM 12, SAVEF
CAIL 12, 0
CAILE 12, 2
PUSHJ P, Y2FIEL
MOVE 12, SAVEF
CAIE 12, 2 ; F=2 → HLT
JRST .+5
HLT: OUTSTR [ASCIZ ⊗
#HALT#⊗]
SKIPE RUNC ; RUNC=0 → NO RUN FILE
JRST ENDRUN
JRST BUTTON ; RETURN CONTROL TO USER
JUMPN 12, CHAR ; F>0 → CHAR
NUM: SETZ 12, ; CLEAR 12 TO ACCUMULATE RESULT
HRRI 13, 0 ; INITIALIZE POINTER ADDRESS
HRLI 13, 360600 ; INITIALIZE BYTE INDICATORS
ILDB 10, 13 ; GET CHARACTER
IDIVI 10, 12 ; GET MOD(10)
IMULI 12, 12 ; ACCUMULATE SUM
ADD 12, 11
TLNE 13, 770000 ; FINISHED WITH BATCH OF 5 BYTES?
JRST .-5 ; NO → GET SOME MORE
TRON 13, 7 ; WAS THIS RX?
JRST .-10 ; NO, BUT NOW IT IS!!!
TLZE 12, 370000 ; DONE → TEST FOR OVERFLOWS
TLO FLAGS, OVFLAG ; YES → SET FLAG
DPB 12, [POINT 30, RA, 35] ; PUT NUM INTO RA
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
CHAR: MOVE 10, RA ; INITIALIZE 10
TLZ 10, 400000 ; IGNORE SIGN
MOVEI 13, 1 ; LOOP COUNTER
SETZ 12, ; ZERO OUT WORK REGISTER
IDIVI 10, 12 ; GET REMAINDER
ADDI 11, 36 ; CONVERT TO CHARACTER CODE
OR 12, 11 ; PUT CHAR INTO WORK REGISTER
ROT 12, -6 ; SHIFT RIGHT ONE BYTE
TRNN 12, 7700 ; TEST FOR 5 BYTES
JRST .-5 ; NO → GET MORE
LSH 12, -6 ; PUT INTO RIGHT POSITION
DPB 12, CPOINT(13) ; PUT INTO RX OR RA
SOJGE 13, .-11 ; ONE MORE TIME?
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
CPOINT: POINT 30, RA, 35
POINT 30, RX, 35
PATCH: BLOCK =100 ;*RES*
SUBTTL MIXIO - I/O button routines
crdpag: 0 ; 0 iff on first page of data file
QREAD: SKIPE CRDBLK ; 0 → NOT INITED
JRST QRD1
INIT 10,
SIXBIT /DSK/
CRDBLK+1
JRST ZDISK ; ERROR RETURN
PUSHJ P,RESCN ;*RES* LOOK FOR NAME ON PREV LINE
PUSHJ P,FINFI2 ;*RES* LOOK IT UP
JRST .+3 ;*RES* RESCN SKIPS 2 IF NO ARG
OUTSTR [ASCIZ ⊗FILE FOR CARD READER INPUT: ⊗]
PUSHJ P,FINFO ;GET FILE DATA
MOVE 10, [XWD BLK, CRDBLK+4] ; PUT DATA IN CRDBLK
BLT 10, CRDBLK+7
LOOKUP 10, CRDBLK+4 ; LOOKUP FILE
JRST .-5 ; ERROR → TRY AGAIN
inbuf 10,
setzm crdpag ; start at page 0.
AOS CRDBLK ; I/0 STATUS WORD ← +1
JRST BUTTON
QRD1: OUTSTR [ASCIZ ⊗READ FILE ALREADY OPEN⊗] ;*RES*
JRST QBUTN ;*RES*
QREADX: RELEAS 10, 0 ; CLOSE AND RELEAS CHANNEL
SETZM CRDBLK ; RESET I/O STATUS WORD
JRST BUTTON
QPUNCH: SKIPE CPNBLK ; 0 → NOT INITED
JRST QPN1
INIT 11, 10 ; INIT IN IMAGE MORE
SIXBIT /DSK/
XWD CPNBLK+1, 0
JRST ZDISK ; ERROR RETURN
PUSHJ P,RESCN ;*RES* LOOK FOR NAME ON PREV LINE
PUSHJ P,FINFI2 ;*RES* LOOK IT UP
JRST .+3 ;*RES* RESCN SKIPS 2 IF NO ARG
OUTSTR [ASCIZ ⊗FILE FOR CARD PUNCH OUTPUT: ⊗]
PUSHJ P,FINFO ; GET FILE DATA
MOVE 10, [XWD BLK, CPNBLK+4] ; PUT DATA IN CPNBLK
BLT 10, CPNBLK+7
ENTER 11, CPNBLK+4 ; ENTER FILE
JRST .-5 ; ERROR → TRY AGAIN
outbuf 11,
AOS CPNBLK ; I/0 STATUS WORD ← +1
JRST BUTTON
QPN1: OUTSTR [ASCIZ ⊗PUNCH FILE ALREADY OPEN⊗] ;*RES*
JRST QBUTN ;*RES*
QPNCHX: RELEAS 11, 0 ; CLOSE AND RELEAS CHANNEL
SETZM CPNBLK ; RESET I/O STATUS WORD
JRST BUTTON
QPRINT: SKIPE PRNBLK ; 0 → NOT INITED
JRST QPR1
INIT 12, 10 ; INIT IN IMAGE MORE
SIXBIT /DSK/
XWD PRNBLK+1, 0
JRST ZDISK ; ERROR RETURN
PUSHJ P,RESCN ;*RES* LOOK FOR NAME ON PREV LINE
PUSHJ P,FINFI2 ;*RES* LOOK IT UP
JRST .+3 ;*RES* RESCN SKIPS 2 IF NO ARG
OUTSTR [ASCIZ ⊗FILE FOR PRINTER OUTPUT: ⊗]
PUSHJ P,FINFO ;GET FILE DATA
MOVE 10, [XWD BLK, PRNBLK+4] ; PUT DATA IN PRNBLK
BLT 10, PRNBLK+7
ENTER 12, PRNBLK+4 ; ENTER FILE
JRST .-5 ; ERROR → TRY AGAIN
outbuf 12,
AOS PRNBLK ; I/0 STATUS WORD ← +1
JRST BUTTON
QPR1: OUTSTR [ASCIZ ⊗PRINT FILE ALREADY OPEN⊗] ;*RES*
JRST QBUTN ;*RES*
QPRNTX: RELEAS 12, 0 ; CLOSE AND RELEAS CHANNEL
SETZM PRNBLK ; RESET I/O STATUS WORD
JRST BUTTON
QBUTN: INCHWL 10 ;*RES* READ REST OF LINE
CAIE 10,12 ;*RES* UP TO THE LF
JRST .-2
JRST BUTTON ;*RES* THEN GO TO BUTTON
COMMENT ⊗ "Input-output" operations.
At present (6-25-70), the only devices planned for this MIX
machine are the following:
card reader `CRD' F=16 chan=10
card punch `CPN' F=17 chan=11
printer `PRN' F=18 chan=12
typewriter(in) `TIN' F=19 chan=13
typewriter(out) `TOT' F=19 chan=14
The simulation of i/o for CRD, CPN, PRN will be done through the
use of disk files.
Each device will have a device block of 8 words, containing
the following information:
word 1 an i/o status word
words 2-4 i/o buffer for the system
words 5-8 file info for LOOKUP or ENTER
TIN and TOT will be done directly to and from the teletype.
In addition, a copy of everything printed on the teletype
during each use of MIXSIM will be saved on a file called
MIXTTY. This will enable the user to obtain hard copies of
everything.
⊗
COMMENT ⊗ This subroutine takes the MIX character in register 10
and puts it into the appropriate place in MIXBUF (using
a byte pointer in 11). If this fills MIXBUF, the routine
moves MIXBUF to the address in MIXAD, increments MIXAD,
resets the byte pointer in 11, and zeros out MIXBUF.
Called by "CTOMIX"
⊗
OPDEF CTOMIX [PUSHJ P, .]
IDPB 10, 11 ; PUT BYTE INTO MIXBUF
TLNE 11, 770000 ; LAST BYTE IN MIXBUF?
POPJ P, ; NO → RETURN
MOVE 10, MIXBUF ; YES → PUT INTO MIX CORE
MOVEM 10, @MIXAD
AOS MIXAD ; INCREMENT MIXAD
MOVE 11, [POINT 6, MIXBUF, 5] ; RESET BYTE POINTER
SETZM MIXBUF ; ZERO OUT MIXBUF
POPJ P, ; RETURN
COMMENT ⊗ This subroutine takes the MIX word in register 10
and moves it to the address in MIXAD.
Called by "WTOMIX"
⊗
OPDEF WTOMIX [PUSHJ P, .]
MOVEM 10, @MIXAD ; PUT INTO MIX CORE
AOS MIXAD ; INCREMENT MIXAD
POPJ P, ; RETURN
COMMENT ⊗ This subroutine is similar to CTOMIX, but instead of
putting the characters into MIXBUF, it takes them out
(resetting MIXBUF and MIXAD when necessary).
Called by "CFRMIX"
⊗
OPDEF CFRMIX [PUSHJ P, .]
TLNE 11, 770000 ; LAST BYTE IN MIXBUF?
JRST .+5 ; NO
MOVE 10, @MIXAD ; YES → GET NEXT ONE
MOVEM 10, MIXBUF
AOS MIXAD ; INCREMENT MIXAD
MOVE 11, [POINT 6, MIXBUF, 5] ; RESET POINTER
ILDB 10, 11 ; GET NEXT CHARACTER
POPJ P, ; RETURN
COMMENT ⊗ This is similarly analagous to WTOMIX.
Called by "WFRMIX"
⊗
OPDEF WFRMIX [PUSHJ P, .]
MOVE 10, @MIXAD ; GET NEXT WORD
AOS MIXAD ; INCREMENT MIXAD
POPJ P, ; RETURN
COMMENT ⊗ The IN instruction ⊗
IN: MOVE 12,MSPEC ; GET MEMORY SPECIFICATIONS
ADDI 12, MC0000 ; RELOCATE SO ADDRESSES MIX-CORE
MOVEM 12, MIXAD ; INITIALIZE MIXAD
LDB 11, [POINT 6, INSTR, 29] ; GET FIELD-BYTE
CAILE 11, =19 ; UNIT NUMBER MUST BE ≤19
JRST ZUNIT ; ERROR
SKIPG 13, UNIN(11) ; 13 ← CHANNEL NUMBER AND
JRST ZUNIT ; ERROR IF ZERO
HLRZ 10, LOCK1(11) ; first we wait for this device to finish anything
JUMPE 10, .+4 ; no input on this device
MOVE 10, (10) ; get time for finishing input
CAMLE 10, EXTIME ; has it happened?
MOVEM 10, EXTIME ; no → make it happen
HRRZ 10, LOCK1(11)
JUMPE 10, .+4 ; no output on this device
MOVE 10, (10) ; get time for finishing output
CAMLE 10, EXTIME ; has it happened?
MOVEM 10, EXTIME ; now it has
HRLZ 10, 12 ; now see if any interlocks on the range to work with
HRR 10, LOCK0(11)
ADD 10, 12
SUB 10, [XWD MC0000, MC0000]
MOVEM 10, MLOCK ; now MLOCK has range descriptor
WWLOCK ; test whether it's OK to use this range
JRST ZWLOCK ; no it isn't
LDB 11, [POINT 6, INSTR, 29]
HLRZ 10, LOCK1(11) ; add device to RLOCKT for read-interlock
JUMPE 10, IN1 ; zero → this device doesn't get entered (should never take this jump)
MOVEM 10, LOCK2 ; save base address of entry in table
HLRZ 10, LOCK0(11) ; this gives total interlock time
ADD 10, EXTIME ; so this is time when device is finally ready
MOVEM 10, @LOCK2 ; a fact we should remember
AOS LOCK2 ; for next part of table entry
MOVE 10, MIXAD ; this is base address of locked-out range
SUBI 10, MC0000 ; make it relative to MC0000
MOVEM 10, @LOCK2 ; and remember it
AOS LOCK2 ; get ready for next part of entry
ADD 10, LOCK0(11) ; this gives final address of range
HRRZS 10 ; get rid of garbage in left half
MOVEM 10, @LOCK2 ; and remember this too
IN1: MOVE 11, [POINT 6, MIXBUF, 5] ; INITIALIZE BYTE POINTER TO MIXBUF
SETZM MIXBUF ; ZERO OUT MIXBUF
JRST @INAD(13) ; GO TO APPROPRIATE ADDRESS
INAD: 0
0
0
0
0
0
0
0
INCRD
0
0
INTIN
0
0
0
0
COMMENT ⊗ The OUT instruction ⊗
OUT: MOVE 12,MSPEC ; GET MEMORY SPECIFICATIONS
ADDI 12, MC0000 ; RELOCATE SO ADDRESSES MIX-CORE
MOVEM 12, MIXAD ; INITIALIZE MIXAD
LDB 11, [POINT 6, INSTR, 29] ; GET FIELD-BYTE
CAILE 11, =19 ; UNIT NUMBER MUST BE ≤19
JRST ZUNIT ; ERROR
SKIPG 13, UNOUT(11) ; 13 ← CHANNEL NUMBER AND
JRST ZUNIT ; ERROR IF ZERO
HLRZ 10, LOCK1(11) ; first we wait for this device to finish anything
JUMPE 10, .+4 ; no input on this device
MOVE 10, (10) ; get time for finishing input
CAMLE 10, EXTIME ; has it happened?
MOVEM 10, EXTIME ; no → make it happen
HRRZ 10, LOCK1(11)
JUMPE 10, .+4 ; no output on this device
MOVE 10, (10) ; get time for finishing output
CAMLE 10, EXTIME ; has it happened?
MOVEM 10, EXTIME ; now it has
HRLZ 10, 12 ; now see if any interlocks on the range to work with
HRR 10, LOCK0(11)
ADD 10, 12
SUB 10, [XWD MC0000, MC0000]
MOVEM 10, MLOCK ; now MLOCK has range descriptor
RRLOCK ; test whether it's OK to use this range
JRST ZRLOCK ; no it isn't
LDB 11, [POINT 6, INSTR, 29]
HRRZ 10, LOCK1(11) ; add device to RLOCKT for read-interlock
JUMPE 10, OUT1 ; zero → this device doesn't get entered (should never take this jump)
MOVEM 10, LOCK2 ; save base address of entry in table
HLRZ 10, LOCK0(11) ; this gives total interlock time
ADD 10, EXTIME ; so this is time when device is finally ready
MOVEM 10, @LOCK2 ; a fact we should remember
AOS LOCK2 ; for next part of table entry
MOVE 10, MIXAD ; this is base address of locked-out range
SUBI 10, MC0000 ; make it relative to MC0000
MOVEM 10, @LOCK2 ; and remember it
AOS LOCK2 ; get ready for next part of entry
ADD 10, LOCK0(11) ; this gives final address of range
HRRZS 10 ; get rid of garbage in left half
MOVEM 10, @LOCK2 ; and remember this too
OUT1: MOVE 11, [POINT 6, MIXBUF, 5] ; INITIALIZE BYTE POINTER TO MIXBUF
SETZM MIXBUF ; ZERO OUT MIXBUF
JRST @OUTAD(13) ; GO TO APPROPRIATE ADDRESS
OUTAD: 0
0
0
0
0
0
0
0
0
OUTCPN
OUTPRN
0
OUTTOT
0
0
0
COMMENT ⊗ These tables are used to convert the F unit number
to i/o channels. A `0' indicates that that form of
i/o cannot be done with that unit.
⊗
UNIN: 0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
10 ; CARD READER
0 ; CARD PUNCH CANNOT DO INPUT
0 ; PRINTER CANNTO DO INPUT
13 ; TYPEWRITER
UNOUT: 0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0 ; CARD READER CANNOT DO OUTPUT
11 ; CARD PUNCH
12 ; PRINTER
14 ; TYPEWRITER
MIXAD: 0 ; CONTAINS ADDRESS OF NEXT MIX WORD TO WORRY ABOUT
MIXBUF: 0 ; BUFFER FOR MIX WORDS
IOBUF: 0 ; BUFFER FOR I/O DEVICES
COUNT: 0
LOCK0: repeat =16 {0} ; this table has interlock times and record lengths
XWD =1000, =15 ; CRD: 1000u and 16 words
XWD =1000, =15 ; CPN: 1000u and 16 words
XWD =750, =23 ; PRN: 750u and 24 words
XWD =2000, =13 ; TIN,TOT: 2000u and 14 words
LOCK1: repeat =16 {0} ; this table has address for interlock tables
XWD CRDLOK, 0 ; CRD: read-interlock
XWD 0, CPNLOK ; CPN: write-interlock
XWD 0, PRNLOK ; PRN: write-interlock
XWD TINLOK, TOTLOK ; Typ: both read and write
LOCK2: 0 ; this is just used for temporary stoarage
COMMENT ⊗ These are the device specific sections.
⊗
; ****** CARD READER
CRDBLK: BLOCK 10
INCRD: SKIPN CRDBLK ; I/O STATUS WORD = 0
JRST ZIOBEG ; → NOT INITED YET
MOVEI 10, =80 ; SET UP COUNTER FOR CHARACTERS
MOVEM 10, COUNT
incrd1: PUSHJ P, GETbyt ; YES → GET NEXT byte
CAIN 10, 15 ; CARRIAGE-RETURN →
JRST incrd2 ; FINISH LINE WITH BLANKS
MOVE 10, ASCMIX(10) ; CONVERT TO MIX CODE
CTOMIX
SOSE COUNT ; BACK FOR MORE
jrst incrd1
JRST incrd3 ; NOW GO TO END OF LINE
incrd2: SETZ 10, ; MIX CODE FOR <BLANK> IS 00
CTOMIX
SOSE COUNT ; BACK FOR MORE
JRST .-3
incrd3: PUSHJ P, GETbyt ; YES → GET NEXT byte
CAIE 10, 12 ; KEEP TRYING UNTIL LINE-FEED
JRST .-2
SETZM CRDBLK ; I/O STATUS WORD ← -1
SOS CRDBLK
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
GETbyt: SOSG CRDBLK+3 ; DECREMENT CHARACTER COUNT
IN 10, ; COUNT EXHAUSTED, NEXT BUFFER
JRST .+4 ; OK, SO CONTINUE
STATZ 10, 20000 ; TEST WHETHER ERROR WAS EOF
JRST ZEOF ; YES
JRST ZINOUT ; SOME OTHER I/O ERROR
ILDB 10, CRDBLK+2 ; GET INPUT WORD
JUMPE 10,GETbyt ;*RES* IGNORE NULLS AT END OF RECORD
move 12,@crdblk+2 ; pick up next word
skipe crdpag ; still on first page ?
jrst getby1 ; no.
setom crdpag ; only make this test once.
move 12,@crdblk+2
came 12,[ascii/COMME/]
popj p,
aos crdblk+2
move 12,@crdblk+2
sos crdblk+2
came 12,[ascii/NT ⊗ /]
popj p,
sosg crdblk+3 ; we have an E directory page.
input 10,
ildb 12,crdblk+2
caie 12,14
jrst .-4
jrst getbyt
getby1: trnn 12,1 ; SOS linenum or like ?
popj p, ; No.
aos crdblk+2 ; Yes, ignore.
movni 12,5
addm 12,crdblk+3
jrst getbyt
; ****** CARD PUNCH
CPNBLK: BLOCK 10
OUTCPN: SKIPN CPNBLK ; I/O STATUS WORD = 0
JRST ZIOBEG ; → NOT INITED YET
MOVEI 10, =80 ; SET UP COUNTER FOR CHARS
MOVEM 10, COUNT
SETZM IOBUF ; ZERO OUT IOBUF
MOVE 12, [POINT 7, IOBUF] ; INITIALIZE BYTE POINTER
SETZ 11, ; FIX 11 SO CFRMIX WORKS FIRST TIME
CFRMIX
MOVE 10, MIXASC(10) ; CONVERT TO ASCII CODE
IDPB 10, 12 ; PUT INTO IOBUF
TLNN 12, 760000 ; LAST BYTE IN IOBUF?
PUSHJ P, PUTWRD ; YES → OUTPUT IT
SOSE COUNT ; BACK FOR MORE
JRST .-6
MOVEI 10, 15 ; NOW OUTPUT C-R, L-F
IDPB 10, 12
MOVEI 10, 12
IDPB 10, 12
PUSHJ P, PUTWRD
SETZM CPNBLK ; I/O STATUS WORD ← -1
SOS CPNBLK
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
PUTWRD: SOSG CPNBLK+3 ; DECREMENT CHARACTER COUNT
OUT 11, ; OUTPUT THIS BUFFER
SKIPA ; SUCCESS
JRST ZINOUT ; ERROR
MOVE 10, IOBUF ; GET OUTPUT WORD
IDPB 10, CPNBLK+2 ; PUT ONTO FILE
SETZM IOBUF ; ZERO OUT IOBUF
MOVE 12, [POINT 7, IOBUF] ; INITIALIZE BYTE POINTER
POPJ P, ; RETURN
; ****** TYPEWRITER (IN)
TINBLK: BLOCK 10
INTIN: MOVEI 10, =70 ; SET UP COUNTER
MOVEM 10, COUNT
INCHWL 10 ; GET FIRST CHAR OF LINE
SKIPA ; FOR FIRST TIME
INCHRW 10 ; GET NEXT CHAR
CAIN 10, 15 ; CARRIAGE-RETURN →
JRST .+6 ; FINISH LINE WITH BLANKS
MOVE 10, ASCMIX(10) ; CONVERT TO MIX CODE
CTOMIX
SOSE COUNT ; BACK FOR MORE
JRST .-6
JRST .+5 ; NOW GO TO END OF LINE
SETZ 10, ; MIX CODE FOR <BLANK> IS 00
CTOMIX
SOSE COUNT ; BACK FOR MORE
JRST .-3
INCHRW 10 ; KEEP TRYING UNTIL LINE-FEED
CAIE 10, 12
JRST .-2
SETZM TINBLK ; I/O STATUS WORD ← -1
SOS TINBLK
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
; ****** TYPEWRITER (OUT)
TOTBLK: BLOCK 10
OUTTOT: MOVEI 10, =70 ; SET UP COUNTER FOR CHARS
MOVEM 10, COUNT
SETZ 11, ; FIX 11 SO CFRMIX WORKS FIRST TIME
CFRMIX
MOVE 10, MIXASC(10) ; CONVERT TO ASCII CODE
OUTCHR 10 ; OUTPUT IT
SOSE COUNT ; BACK FOR MORE
JRST .-4
MOVEI 10, 15 ; NOW OUTPUT C-R, L-F
OUTCHR 10
MOVEI 10, 12
OUTCHR 10
SETZM TOTBLK ; I/O STATUS WORD ← -1
SOS TOTBLK
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
; ****** PRINTER
PRNBLK: BLOCK 10
OUTPRN: SKIPN PRNBLK ; I/O STATUS WORD = 0
JRST ZIOBEG ; → NOT INITED YET
MOVEI 10, =120 ; SET UP COUNTER FOR CHARS
MOVEM 10, COUNT
SETZM IOBUF ; ZERO OUT IOBUF
MOVE 12, [POINT 7, IOBUF] ; INITIALIZE BYTE POINTER
SETZ 11, ; FIX 11 SO CFRMIX WORKS FIRST TIME
CFRMIX
MOVE 10, MIXASC(10) ; CONVERT TO ASCII CODE
IDPB 10, 12 ; PUT INTO IOBUF
TLNN 12, 760000 ; LAST BYTE IN IOBUF?
PUSHJ P, PRNWRD ; YES → OUTPUT IT
SOSE COUNT ; BACK FOR MORE
JRST .-6
MOVEI 10, 15 ; NOW OUTPUT C-R, L-F
IDPB 10, 12
SKIPN NOJECT ;*RES* SEE IF PRINT OVER PERF
JRST .+6 ;*RES* NO
MOVEI 10,177 ;*RES*
IDPB 10,12 ;*RES* LPT LIKES 177&21 FOR LF ALSO
MOVEI 10,21 ;*RES*
IDPB 10,12 ;*RES*
JRST .+3 ;*RES*
MOVEI 10, 12
IDPB 10, 12
PUSHJ P, PRNWRD
SETZM PRNBLK ; I/O STATUS WORD ← -1
SOS PRNBLK
JRST MIXMON ; RETURN TO INSTRUCTION INTERPRETER
PRNWRD: SOSG PRNBLK+3 ; DECREMENT CHARACTER COUNT
OUT 12, ; OUTPUT THIS BUFFER
SKIPA ; SUCCESS
JRST ZINOUT ; ERROR
MOVE 10, IOBUF ; GET OUTPUT WORD
IDPB 10, PRNBLK+2 ; PUT ONTO FILE
SETZM IOBUF ; ZERO OUT IOBUF
MOVE 12, [POINT 7, IOBUF] ; INITIALIZE BYTE POINTER
POPJ P, ; RETURN
; these are the other i/o related operations
IOC: MOVE 12,MSPEC ; the only one we'll allow is IOC 0,(18)
JUMPN 12, ZIOC ; so if M in non-zero, it's an error
LDB 11, [POINT 6, INSTR, 29] ; now get F-field
CAIE 11, =18 ; if F 18?
JRST ZIOC ; no → error
MOVE 10, PRNLOK ; wait until printer is finished
CAMLE 10, EXTIME ; do this by changing EXTIME if necessary
MOVEM 10, EXTIME ; it is necessary
MOVE 10, EXTIME ; now we must interlock the printer for the form-feed
ADDI 10, =1000 ; we will use 1000u
MOVEM 10, PRNLOK ; establish interlock time
SETOM PRNLOK+1 ; use range -1:-1
SETOM PRNLOK+2
MOVEI 10, 6430 ;*RES* this is a carriage-return, form-feed
MOVEM 10, IOBUF ; so this is <null><null><null><c-r><f-f>
SKIPN PRNBLK ; is printer inited?
JRST ZIOBEG ; no → txis is an error
PUSHJ P,PRNWRD ;*RES* now send the new page stuff
SETOM PRNBLK ; i/o status word ← -1
JRST MIXMON ; and return to instruction interpreter
JBUS: MOVE 12,MSPEC ; first we see whether it is JBUS *
CAMN 12, ISPEC ; does it match address of present instruction
JRST JBUS1 ; yes → special case
MOVSI 10, (<CAMGE 10,>) ; no → use same routine as JRED
JRST JRB
JBUS1: LDB 11, [POINT 6, INSTR, 29] ; get F-field
CAIL 11, =16 ; is it a legal unit?
CAILE 11, =19
JRST ZDEV ; no → error
MOVE 10, EXTIME ; save EXTIME so we get a count of number of executions
MOVEM 10, JBUSX
HLRZ 10, LOCK1(11) ; get address to check for input busy
JUMPE 10, .+4 ; no such address → don't check
MOVE 10, (10) ; get time when device is finished
CAML 10, EXTIME ; and see whether it has happened
MOVEM 10, EXTIME ; no → change so it has
HRRZ 10, LOCK1(11) ; address to check for output busy
JUMPE 10, .+4 ; no address → don't check
MOVE 10, (10) ; get time device is finished
CAML 10, EXTIME ; and see whether time has come pass
MOVEM 10, EXTIME ; no → now it has
MOVE 10, EXTIME ; calculate number of executions
SUBM 10, JBUSX ; new EXTIME - old EXTIME
SKIPG JBUSX ; any at all?
SETZM JBUSX ; no → make sure it's zero
JRST MIXMON ; so device is no longer busy
JRED: MOVSI 10, (<CAML 10,>) ; so we can use same routine for JBUS, JRED
JRB: HLLM 10, JRB1 ; fix so we do the right compares
HLLM 10, JRB2
MOVE 12,MSPEC ; get address to jump to
TESTM ; is is valid?
LDB 11, [POINT 6, INSTR, 29] ; get F-field
CAIL 11, =16 ; is it valid?
CAILE 11, =19
JRST ZDEV ; no → error
HLRZ 10, LOCK1(11) ; test for input busy
JUMPE 10, .+4 ; no input
MOVE 10, (10) ; get execution time for finishing
JRB1: EXTIME ; this is the crucial compare
JRST MIXMON ; don't want to jump
HRRZ 10, LOCK1(11) ; test for output busy
JUMPE 10, .+4
MOVE 10, (10)
JRB2: EXTIME ; another crucial compare
JRST MIXMON ; don't want to jump
JRST JMP ; we do want to jump
JBUSX: 0 ; this will contain the number of executions of JBUS *
↓NOMIX←←1; Inhibit assembly of all but essential parts of MIXAL.